Objective-C




范圣刚,princetoad@gmail.com,www.tfan.org
• Objc 基础
• 通过⼀一个RandomPossessions 的⼩小程序看⼀一下有
 关:类,实例,对象,消息,初始化⽅方法,类⽅方
 法,数组,字符串和格式化字符串,访问器,异
 常
Objective-C
• iOS 应⽤用
• Objective-C: C 语⾔言的扩展
• Cocoa Touch: Objective-C 类的集合
• ⾯面向对象编程(object-oriented programming)
对象
Party的表⽰示
• 属性
 • 名称
 • ⽇日期
 • 受邀⼈人列表
• 操作
 • 发送email提醒
 • 打印名称标签
 • 取消party
C
• 结构体
    • 数据成员
    • 类型和名称
• malloc
• C 函数
Class
•类
•实例
•结构体成员和实例变量
•⽅方法:名称,返回值类型,参
数列表,实例变量访问
•运⾏行⽅方法:message
使⽤用实例
使⽤用实例
• 使⽤用类的实例
• 指向对象的变量
• 指针变量 -> 对象在内存中的地址
• 指向对象的变量声明:Party *partyInstance;
• 只是⼀一个可以指向 Party 对象的变量,不是对象本
⾝身。
创建对象
• 对象的⽣生命周期:被创建,发送消息,不⽤用的时
 候销毁
• alloc 消息:Party *partyInstance = [Party alloc];
• 当你拥有⼀一个指向实例的指针时,就可以向它发
 送消息
• 第⼀一个消息 -> initialization 消息:[partyInstance
 init];
• 合并:Party *partyInstance = [[Party alloc] init];
• nested message send
发送消息
消息剖析
• 中括号中
• 三个部分
 • receiver: ⼀一个指向被要求执⾏行⽅方法的对象的指针
 • selector: 要执⾏行的⽅方法的名称
 • arguments: 作为参数提供给⽅方法的值
• [partyInstance addAttendee:somePerson]
 • 发送 addAttendee: 消息给 partyInstance(receiver) 触发
   addAttendee: ⽅方法(通过 selector 命名)并且传⼊入
   somePerson(⼀一个argument)

• message 可以有⼀一个参数,多个参数,或者没有参数
发送消息


receiver 是被发送消息的   selector 是被触发的⽅方法
                                       arguments 被⽅方法使⽤用
对象指针               的名称


 [ partyInstance addAttendee: somePerson
                      withDish: deviledEggs ]
其他语⾔言
   partyInstance.addAttendeeWithDish(somePerson, deviledEggs)

Objective-C
  [partyInstance addAttendee:somePerson withDish:deviledEggs];
销毁对象
• partyInstance = nil;
nil
 • if (venue == nil) ...
 • if (!venue) ...
 • 向 nil 变量发送消息
 • if (venue) { [venue sendConfirmation]; }
  • nil-check 是没有必要的
开始 RandomPossessions
把模板代码换成创建和销毁数组实例

 #import <Foundation/Foundation.h>

 int main(int argc, const char * argv[])
 {

      @autoreleasepool {

 //         // insert code here...
 //         NSLog(@"Hello, World!");
          // 创建⼀一个 mutable 数组对象,把它的地址保存到 items 变量
          NSMutableArray *items = [[NSMutableArray alloc] init];

          // 销毁 items 指向的对象
          items = nil;

      }
      return 0;

 }
• ⼀一但实例化完数组以后,我们就可以给它发送消
     息了,例如 addObject: 和 insertObject:atIndex


int main(int argc, const char * argv[])
{

     @autoreleasepool {

//        // insert code here...
//        NSLog(@"Hello, World!");
        // 创建⼀一个 mutable 数组对象,把它的地址保存到 items 变量
        NSMutableArray *items = [[NSMutableArray alloc] init];

        // 向 items 发送 addObject: 消息,每次传递⼀一个字符串
        [items addObject:@"One"];
        [items addObject:@"Two"];
        [items addObject:@"Three"];

        // 发送另外⼀一个消息 insertObject:atIndex 给同样的数组对象
        [items insertObject:@"Zero" atIndex:0];
• 为了确认这些 string 被添加到了数组,我们来加
⼀一段代码把它们打印出来

• 构建并运⾏行,看⼀一下控制台的输出
  // 遍历数组
  for (int i=0; i < [items count]; i++) {
      // 隐式发送 description 消息
      NSLog(@"%@", [items objectAtIndex:i]);
  }
创建字符串
• [items addObject:@”One”];
• @符号 + 字符串 = Objective-C 中的硬编码字符串
• NSString 的实例
• alloc?
• @:仅针对 NSString 的⽅方便的⽣生成字符串的缩写
 NSString *myString = @"Hello, World!";
 int len = [myString length];

 len = [@"Hello, World" length];

 myString = [[NSString alloc] initWithString:@"Hello, World!"];
 len = [myString length];
格式化字符串
• NSLog 打印到控制台,接收可变数量的参数
• 第⼀一个参数是必须的,⽽而且必须是 NSString 实例,称
 作 format string,包含⽂文本和⼀一些 token。

• token 以百分号%作为前缀
• 每⼀一个传给函数的附加参数替换掉 format string 中的
 ⼀一个token
• token 同时也指定了他们对应的参数的类型
 int a = 1;
 float b = 2.5;
 char c = 'A';
 NSLog(@"整数: %d 浮点数: %f 字符: %c", a, b, c);
%@
• 任何对象
• description 消息,返回⼀一个 NSString
• 所有对象都实现了 description 消息
NSArray 和 NSMutableArray
• NSArray
 • 不可变数组
 • 实例化之后就不能再增加或者删除对象了
• NSMutableArray
 • NSArray ⼦子类
 • 可变数组
 • 可以被修改(动态增加删除对象)
指针,引⽤用和内存地址
数组能放什么?
• 数组只能持有 Objective-C 对象的引⽤用
• 基本数据类型和 C 结构体不能增加到数组
• ⼀一个单独的数组可以包含不同类型的对象
• 和强类型语⾔言不同
数组操作
• ⼤大⼩小:int numberOfObjects = [array count];
• addObject: 在数组最后增加对象
• insertObject:atIndex: 在特定位置插⼊入对象
• 注意:不能往数组中增加 nil ,可以使⽤用 NSNull
 • [array addObject:[NSNull null]]
• objectAtIndex: 获取数据
⼦子类化⼀一个 Objective-C 类
• 层次结构 (hierarchy)
• 只有⼀一个超类(superclass)
• NSObject
 • root class
 • ⾓角⾊色是实现所有 Cocoa Touch 中的对象的基本⾏行为
 • alloc, init, description
类的层次结构
• 扩展
• 重写
创建⼀一个NSObject 的⼦子类
• target 勾选
• BNRItem, BNRItem.h, BNRItem.m
• 保留所有的 C 语⾔言关键字
• Objective-C 额外的关键字使⽤用@前缀区分
• 关键字 @interface 在 Objective-C 中声明⼀一个类
• 冒号后跟⽗父类
• 只允许单⼀一继承
 • @interface ClassName : SuperclassName
 • @end 指⽰示类已经被完全声明了
实例变量
类的实例变量紧跟类的声明之后,在
⼤大括号中进⾏行声明

#import <Foundation/Foundation.h>

@interface BNRItem : NSObject
{
    NSString *itemName;
    NSString *serialNumber;
    int valueInDollars;
    NSDate *dateCreated;
}

@end
BNRItem 实例
访问器⽅方法
• 有了实例变量之后,要能够 get,或 set 他们的值
• get/set 实例变量的⽅方法称作 accessors, 或者分别
 叫做getters 和 setters.
• Objective-C 的 setter ⽅方法名:set + 实例变量名
• getter ⽅方法名:和实例变量名⼀一样
BNRItem 访问器⽅方法
#import <Foundation/Foundation.h>

@interface BNRItem : NSObject
{
    NSString *itemName;
    NSString *serialNumber;
    int valueInDollars;
    NSDate *dateCreated;
}

- (void)setItemName:(NSString *)str;
- (NSString *)itemName;

- (void)setSerialNumber:(NSString *)str;
- (NSString *)serialNumber;

- (void)setValueInDollars:(int)i;
- (int)valueInDollars;

- (NSDate *)dateCreated;

@end
实例⽅方法
    • description
    • 重写:在实现⽂文件中定义,不需要再做声明
// 重写 description
- (NSString *)description
{
    NSString *descriptionString =
    [[NSString alloc] initWithFormat:@"%@ (%@): 价值 $%d, 登记
⽇日期 %@",
     itemName, serialNumber, valueInDollars, dateCreated];

    return descriptionString;
}
初始化器
• alloc -> ⽣生成⼀一个实例,返回⼀一个指向它的指针
• init -> 给所有的实例变量初始化值
• ⾃自定义初始化过程简化代码
• 命名习惯:以init开头
BNRItem 的 Initializer
• ⽅方法名(或者叫selector)是:
 initWithItemName:valueInDollars:serialNumber:
• 这个selector 具有三个 label:initWithItemName:,
 valueInDollars:, 和 serialNumber:。表明⽅方法接收三
 个参数
• 这些参数每个都有⼀一个类型和⼀一个参数名
• 类型在圆括号中,参数名紧跟类型
    }
    - (id)initWithItemName:(NSString *)name
            valueInDollars:(int)value
              serialNumber:(NSString *)sNumber;
    - (void)setItemName:(NSString *)str;
id
• 返回值类型是id
• 指向任意对象的指针
• BNRItem * ?
• ⼦子类化的问题
isa
• 从 initializer 返回的对象的类型我们是知道的(向
  类发送 alloc )
• 对象⾃自⾝身也知道它⾃自⼰己的类型 isa 指针
• 每个对象都有⼀一个名为 isa 的实例变量
• 当⼀一个实例通过向类发送 alloc 创建的时候,类把
  返回的对象的 isa 实例变量设成指回到⽣生成它的类
• isa 指针的意思就是说这个对象是⼀一个这个类的实
  例
isa 指针
实现designated initializer
     • 第⼀一件事,使⽤用 super 调⽤用超类的初始化器
     • 最后,使⽤用 self 返回成功初始化过的对象
// 实现初始化⽅方法
- (id)initWithItemName:(NSString *)name valueInDollars:(int)value
serialNumber:(NSString *)sNumber
{
    // 调⽤用⽗父类的指定的初始化器
    self = [super init];

    // 给实例变量初始化值
    [self setItemName:name];
    [self setSerialNumber:sNumber];
    [self setValueInDollars:value];
    dateCreated = [[NSDate alloc] init];

    // 返回初始化对象的地址
    return self;
}
理解 self
• 在⽅方法内部,self 是隐式的本地变量
• 不需要声明,⾃自动设成指向被发送消息的对象
• 可以⽤用于给⾃自⾝身发消息的情况下
• return self;
理解 super
• 重写⽅方法时保持超类⽅方法中的操作,在其上增加
 新的内容
• super:编译器指⽰示符
• 指定名称的⽅方法的查找顺序:对象类⾃自⾝身 -> 超类
 -> 超类的超类
• 给 super 发消息,直接跳过 self 本⾝身, 从其超类
 开始
• initializer 失败的话返回 nil
• self = [super init];
其他初始化器以及初始化链
 • ⼀一个或多个初始化⽅方法
 • 初始化⽅方法链式调⽤用的好处
   • 减少出错的机会
   • 代码更容易维护
// 使⽤用初始化⽅方法链,没有的参数可以传⼊入默认值
- (id)initWithItemName:(NSString *)name
{
    return [self initWithItemName:name
                   valueInDollars:0
                     serialNumber:@""];
}
重写 init



- (id)init
{
    return [self initWithItemName:@"Item"
                   valueInDollars:0
                     serialNumber:@""];
}
Initializer 链
initializer 简单规则
• 类从其超类继承了所有的 initializer,同时可以根据
 其⺫⽬目的任意增加
• 每个类选择⼀一个 initializer 作为其 designated
 initializer
• designated initializer 调⽤用超类的 designated
 initializer
• 类的任意其他 initializer 调⽤用类的 designated
 initializer
• 如果类声明了⼀一个和其超类不同的 designated
 initializer,超类的 designated initializer 必须被重写
 来调⽤用新的 designated initializer
使⽤用 initializer
• 检查重写的 init 是否⽣生效
• 使⽤用 designated initializer 替换掉设置实例变量的
 代码
类⽅方法
• ⽅方法
 • 实例⽅方法
 • 类⽅方法
• 实例⽅方法被发送给类的实例(像init)
• 类⽅方法被发送给类本⾝身(像alloc)
• 类⽅方法⼀一般不是被⽤用来创建⼀一个类的新的实例,
 就是⽤用来提取类的⼀一些全局属性
• 类⽅方法不能在实例上操作,或者访问实例变量
声明类⽅方法
• 实例⽅方法的声明: 在返回值前⾯面 使⽤用减号“-” 表⽰示
• 类⽅方法的声明:使⽤用加号“+” 字符
• convenience method:stringWithFormat,
 randomItem, 返回⾃自⾝身类型的对象
• 类⽅方法中的 self
 • 指向类本⾝身,⽽而不是实例
 • ⼦子类调⽤用的问题
测试⼦子类

 for (int i=0; i<10; i++) {
     BNRItem *p = [BNRItem randomItem];
     [items addObject:p];
 }

 for (int i = 0; i < 10; i++) {
     NSLog(@"%@", [items objectAtIndex:i]);
 }
异常和⽆无法识别的 Selectors
异常
• ⼀一个对象只会响应它的类实现了相关⽅方法的消息
• 动态类型的objc,编译时⽆无法确定
• 异常exception,run-time errors(运⾏行时错误,和
 编译时错误相对compile-time errors)
快速枚举

 for (int i = 0; i < 10; i++) {
     NSLog(@"%@", [items objectAtIndex:i]);
 }




• Objective-C 2.0 引⼊入了fast enumeration
 for (BNRItem *item in items) {
     NSLog(@"%@", item);
 }

02 Objective-C

  • 1.
  • 2.
    • Objc 基础 •通过⼀一个RandomPossessions 的⼩小程序看⼀一下有 关:类,实例,对象,消息,初始化⽅方法,类⽅方 法,数组,字符串和格式化字符串,访问器,异 常
  • 3.
    Objective-C • iOS 应⽤用 •Objective-C: C 语⾔言的扩展 • Cocoa Touch: Objective-C 类的集合 • ⾯面向对象编程(object-oriented programming)
  • 4.
  • 5.
    Party的表⽰示 • 属性 •名称 • ⽇日期 • 受邀⼈人列表 • 操作 • 发送email提醒 • 打印名称标签 • 取消party
  • 6.
    C • 结构体 • 数据成员 • 类型和名称 • malloc • C 函数
  • 7.
  • 8.
  • 9.
    使⽤用实例 • 使⽤用类的实例 • 指向对象的变量 •指针变量 -> 对象在内存中的地址 • 指向对象的变量声明:Party *partyInstance; • 只是⼀一个可以指向 Party 对象的变量,不是对象本 ⾝身。
  • 10.
    创建对象 • 对象的⽣生命周期:被创建,发送消息,不⽤用的时 候销毁 •alloc 消息:Party *partyInstance = [Party alloc]; • 当你拥有⼀一个指向实例的指针时,就可以向它发 送消息 • 第⼀一个消息 -> initialization 消息:[partyInstance init]; • 合并:Party *partyInstance = [[Party alloc] init]; • nested message send
  • 11.
  • 12.
    消息剖析 • 中括号中 • 三个部分 • receiver: ⼀一个指向被要求执⾏行⽅方法的对象的指针 • selector: 要执⾏行的⽅方法的名称 • arguments: 作为参数提供给⽅方法的值 • [partyInstance addAttendee:somePerson] • 发送 addAttendee: 消息给 partyInstance(receiver) 触发 addAttendee: ⽅方法(通过 selector 命名)并且传⼊入 somePerson(⼀一个argument) • message 可以有⼀一个参数,多个参数,或者没有参数
  • 13.
    发送消息 receiver 是被发送消息的 selector 是被触发的⽅方法 arguments 被⽅方法使⽤用 对象指针 的名称 [ partyInstance addAttendee: somePerson withDish: deviledEggs ]
  • 14.
    其他语⾔言 partyInstance.addAttendeeWithDish(somePerson, deviledEggs) Objective-C [partyInstance addAttendee:somePerson withDish:deviledEggs];
  • 15.
  • 16.
    nil • if(venue == nil) ... • if (!venue) ... • 向 nil 变量发送消息 • if (venue) { [venue sendConfirmation]; } • nil-check 是没有必要的
  • 17.
  • 18.
    把模板代码换成创建和销毁数组实例 #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { // // insert code here... // NSLog(@"Hello, World!"); // 创建⼀一个 mutable 数组对象,把它的地址保存到 items 变量 NSMutableArray *items = [[NSMutableArray alloc] init]; // 销毁 items 指向的对象 items = nil; } return 0; }
  • 19.
    • ⼀一但实例化完数组以后,我们就可以给它发送消 息了,例如 addObject: 和 insertObject:atIndex int main(int argc, const char * argv[]) { @autoreleasepool { // // insert code here... // NSLog(@"Hello, World!"); // 创建⼀一个 mutable 数组对象,把它的地址保存到 items 变量 NSMutableArray *items = [[NSMutableArray alloc] init]; // 向 items 发送 addObject: 消息,每次传递⼀一个字符串 [items addObject:@"One"]; [items addObject:@"Two"]; [items addObject:@"Three"]; // 发送另外⼀一个消息 insertObject:atIndex 给同样的数组对象 [items insertObject:@"Zero" atIndex:0];
  • 20.
    • 为了确认这些 string被添加到了数组,我们来加 ⼀一段代码把它们打印出来 • 构建并运⾏行,看⼀一下控制台的输出 // 遍历数组 for (int i=0; i < [items count]; i++) { // 隐式发送 description 消息 NSLog(@"%@", [items objectAtIndex:i]); }
  • 21.
    创建字符串 • [items addObject:@”One”]; •@符号 + 字符串 = Objective-C 中的硬编码字符串 • NSString 的实例 • alloc? • @:仅针对 NSString 的⽅方便的⽣生成字符串的缩写 NSString *myString = @"Hello, World!"; int len = [myString length]; len = [@"Hello, World" length]; myString = [[NSString alloc] initWithString:@"Hello, World!"]; len = [myString length];
  • 22.
    格式化字符串 • NSLog 打印到控制台,接收可变数量的参数 •第⼀一个参数是必须的,⽽而且必须是 NSString 实例,称 作 format string,包含⽂文本和⼀一些 token。 • token 以百分号%作为前缀 • 每⼀一个传给函数的附加参数替换掉 format string 中的 ⼀一个token • token 同时也指定了他们对应的参数的类型 int a = 1; float b = 2.5; char c = 'A'; NSLog(@"整数: %d 浮点数: %f 字符: %c", a, b, c);
  • 23.
    %@ • 任何对象 • description消息,返回⼀一个 NSString • 所有对象都实现了 description 消息
  • 24.
    NSArray 和 NSMutableArray •NSArray • 不可变数组 • 实例化之后就不能再增加或者删除对象了 • NSMutableArray • NSArray ⼦子类 • 可变数组 • 可以被修改(动态增加删除对象)
  • 25.
  • 26.
    数组能放什么? • 数组只能持有 Objective-C对象的引⽤用 • 基本数据类型和 C 结构体不能增加到数组 • ⼀一个单独的数组可以包含不同类型的对象 • 和强类型语⾔言不同
  • 27.
    数组操作 • ⼤大⼩小:int numberOfObjects= [array count]; • addObject: 在数组最后增加对象 • insertObject:atIndex: 在特定位置插⼊入对象 • 注意:不能往数组中增加 nil ,可以使⽤用 NSNull • [array addObject:[NSNull null]] • objectAtIndex: 获取数据
  • 28.
    ⼦子类化⼀一个 Objective-C 类 •层次结构 (hierarchy) • 只有⼀一个超类(superclass) • NSObject • root class • ⾓角⾊色是实现所有 Cocoa Touch 中的对象的基本⾏行为 • alloc, init, description
  • 29.
  • 30.
    创建⼀一个NSObject 的⼦子类 • target勾选 • BNRItem, BNRItem.h, BNRItem.m • 保留所有的 C 语⾔言关键字 • Objective-C 额外的关键字使⽤用@前缀区分 • 关键字 @interface 在 Objective-C 中声明⼀一个类 • 冒号后跟⽗父类 • 只允许单⼀一继承 • @interface ClassName : SuperclassName • @end 指⽰示类已经被完全声明了
  • 31.
    实例变量 类的实例变量紧跟类的声明之后,在 ⼤大括号中进⾏行声明 #import <Foundation/Foundation.h> @interface BNRItem: NSObject { NSString *itemName; NSString *serialNumber; int valueInDollars; NSDate *dateCreated; } @end
  • 32.
  • 33.
    访问器⽅方法 • 有了实例变量之后,要能够 get,或set 他们的值 • get/set 实例变量的⽅方法称作 accessors, 或者分别 叫做getters 和 setters. • Objective-C 的 setter ⽅方法名:set + 实例变量名 • getter ⽅方法名:和实例变量名⼀一样
  • 34.
    BNRItem 访问器⽅方法 #import <Foundation/Foundation.h> @interfaceBNRItem : NSObject { NSString *itemName; NSString *serialNumber; int valueInDollars; NSDate *dateCreated; } - (void)setItemName:(NSString *)str; - (NSString *)itemName; - (void)setSerialNumber:(NSString *)str; - (NSString *)serialNumber; - (void)setValueInDollars:(int)i; - (int)valueInDollars; - (NSDate *)dateCreated; @end
  • 35.
    实例⽅方法 • description • 重写:在实现⽂文件中定义,不需要再做声明 // 重写 description - (NSString *)description { NSString *descriptionString = [[NSString alloc] initWithFormat:@"%@ (%@): 价值 $%d, 登记 ⽇日期 %@", itemName, serialNumber, valueInDollars, dateCreated]; return descriptionString; }
  • 36.
    初始化器 • alloc ->⽣生成⼀一个实例,返回⼀一个指向它的指针 • init -> 给所有的实例变量初始化值 • ⾃自定义初始化过程简化代码 • 命名习惯:以init开头
  • 37.
    BNRItem 的 Initializer •⽅方法名(或者叫selector)是: initWithItemName:valueInDollars:serialNumber: • 这个selector 具有三个 label:initWithItemName:, valueInDollars:, 和 serialNumber:。表明⽅方法接收三 个参数 • 这些参数每个都有⼀一个类型和⼀一个参数名 • 类型在圆括号中,参数名紧跟类型 } - (id)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber; - (void)setItemName:(NSString *)str;
  • 38.
  • 39.
    isa • 从 initializer返回的对象的类型我们是知道的(向 类发送 alloc ) • 对象⾃自⾝身也知道它⾃自⼰己的类型 isa 指针 • 每个对象都有⼀一个名为 isa 的实例变量 • 当⼀一个实例通过向类发送 alloc 创建的时候,类把 返回的对象的 isa 实例变量设成指回到⽣生成它的类 • isa 指针的意思就是说这个对象是⼀一个这个类的实 例
  • 40.
  • 41.
    实现designated initializer • 第⼀一件事,使⽤用 super 调⽤用超类的初始化器 • 最后,使⽤用 self 返回成功初始化过的对象 // 实现初始化⽅方法 - (id)initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber { // 调⽤用⽗父类的指定的初始化器 self = [super init]; // 给实例变量初始化值 [self setItemName:name]; [self setSerialNumber:sNumber]; [self setValueInDollars:value]; dateCreated = [[NSDate alloc] init]; // 返回初始化对象的地址 return self; }
  • 42.
    理解 self • 在⽅方法内部,self是隐式的本地变量 • 不需要声明,⾃自动设成指向被发送消息的对象 • 可以⽤用于给⾃自⾝身发消息的情况下 • return self;
  • 43.
    理解 super • 重写⽅方法时保持超类⽅方法中的操作,在其上增加 新的内容 • super:编译器指⽰示符 • 指定名称的⽅方法的查找顺序:对象类⾃自⾝身 -> 超类 -> 超类的超类 • 给 super 发消息,直接跳过 self 本⾝身, 从其超类 开始 • initializer 失败的话返回 nil • self = [super init];
  • 44.
    其他初始化器以及初始化链 • ⼀一个或多个初始化⽅方法 • 初始化⽅方法链式调⽤用的好处 • 减少出错的机会 • 代码更容易维护 // 使⽤用初始化⽅方法链,没有的参数可以传⼊入默认值 - (id)initWithItemName:(NSString *)name { return [self initWithItemName:name valueInDollars:0 serialNumber:@""]; }
  • 45.
    重写 init - (id)init { return [self initWithItemName:@"Item" valueInDollars:0 serialNumber:@""]; }
  • 46.
  • 47.
    initializer 简单规则 • 类从其超类继承了所有的initializer,同时可以根据 其⺫⽬目的任意增加 • 每个类选择⼀一个 initializer 作为其 designated initializer • designated initializer 调⽤用超类的 designated initializer • 类的任意其他 initializer 调⽤用类的 designated initializer • 如果类声明了⼀一个和其超类不同的 designated initializer,超类的 designated initializer 必须被重写 来调⽤用新的 designated initializer
  • 48.
    使⽤用 initializer • 检查重写的init 是否⽣生效 • 使⽤用 designated initializer 替换掉设置实例变量的 代码
  • 49.
    类⽅方法 • ⽅方法 •实例⽅方法 • 类⽅方法 • 实例⽅方法被发送给类的实例(像init) • 类⽅方法被发送给类本⾝身(像alloc) • 类⽅方法⼀一般不是被⽤用来创建⼀一个类的新的实例, 就是⽤用来提取类的⼀一些全局属性 • 类⽅方法不能在实例上操作,或者访问实例变量
  • 50.
    声明类⽅方法 • 实例⽅方法的声明: 在返回值前⾯面使⽤用减号“-” 表⽰示 • 类⽅方法的声明:使⽤用加号“+” 字符 • convenience method:stringWithFormat, randomItem, 返回⾃自⾝身类型的对象 • 类⽅方法中的 self • 指向类本⾝身,⽽而不是实例 • ⼦子类调⽤用的问题
  • 51.
    测试⼦子类 for (inti=0; i<10; i++) { BNRItem *p = [BNRItem randomItem]; [items addObject:p]; } for (int i = 0; i < 10; i++) { NSLog(@"%@", [items objectAtIndex:i]); }
  • 52.
  • 53.
    异常 • ⼀一个对象只会响应它的类实现了相关⽅方法的消息 • 动态类型的objc,编译时⽆无法确定 •异常exception,run-time errors(运⾏行时错误,和 编译时错误相对compile-time errors)
  • 54.
    快速枚举 for (inti = 0; i < 10; i++) { NSLog(@"%@", [items objectAtIndex:i]); } • Objective-C 2.0 引⼊入了fast enumeration for (BNRItem *item in items) { NSLog(@"%@", item); }