开发 iOS 程序需要使用 Objective-C 语言和 Cocoa Touch 框架。Objective-C 源于 C 语言,是 C 语言的扩展。 Cocoa Touch 框架是一个 Objective-C 类的集合。本篇文章用来介绍一些 Objective-C 基础知识。
假设有一场聚会。该聚会有若干特有的属性,例如聚会的名称,日期和一根受邀请的名单。此外,还有 "聚会" 需要做些事情,比如向受邀请者发送一封提醒邮件,或者取消聚会。
如果使用 C 语言,那么我们可以定义一个 结构体 ,用于保存这场聚会的数据类型。
如果使用 Objective-C 来定义这些数据类型,我们就需要用到 类 。 类就像是制造汽车的工厂,通过工厂(类:聚会)我们可以制造汽车(具体的某一场特性的聚会),这些汽车都是工厂的的实例,每个实例对象都能为某一个特定的聚会保存数据。
所有的对象,都是在内存中的一块数据,类似于结构体。对象要通过实例变量保存属性(例如:汽车的颜色,形状,型号。聚会的名称,等都是属性)。在 Objective-C 中实例变量名之前通常会加上一个下划线。因此,我们的 Party 对象定义实例变量: _name(名称),_date(日期),_budget(预算)
C 结构是一块内存,对象也是一块内存。C 结构有数据成员,每个数据成员有自己的名称和类型。类似的对象有自己的实例变量,每个实例变量有自己的类型和名称。两者之间有一个重要的差别:类有方法。方法有自己的名称,返回类型和传入的参数。此外方法还可以访问对象的实例变量。要调用某个对象的方法,可以向该对象发送响应的 消息
要使用某个类的对象,就需要必须先得到一个指向该对象的变量。 这类 "指针变量" 保存的就是对象在内存中的地址。申明实例 Party * partyInstance 。知识创建了一个对阵,并没有创建任何对象,仅仅申明了一个可以指向某个 Party 的指针变量。
创建对象
对象是有生命周期的,出生到死亡。首先是被创建出来,之后介绍消息,最后不需要的时候要被释放。
创建类实例变量 Party * partyInstance = [[Party alloc] init]; 这种完成初始化的方法叫做 "嵌套消息发送",在 oc 编程中是很常见的。
发送消息
一旦某个对象完成了初始化,就可以向其发送消息。消息必须写到一个方括号正,一个消息包含三个部分:
1. 接收方 :指针,指向执行方法的对象
2. 选择器 :需要执行方法的方法名
3. 实参 :一边两形式传给方法的数值
下面我们以 Party 为例,向 Party 发送 addAttendee: 消息 [partyInstance addAttendee:somePerson] ,这里我们向 partyInstance(接收方) 发送 addAttendee: 方法(取决于选择器)并传入 somePerson(实参);在 iOS 中可以有很多参数,也可以没有参数
释放对象
将指向对象的变量设置为 nil,可以要求程序释放该对象; partyInstance = nil; 表示会释放 partyInstance 变量所指向的对象;在 iOS 中允许向 nil 发送消息。
选择 Xcode,进入命令行工具,RandomItems 的第一个版本将创建一个包含 4 个字符串的数组。 数组 包含一组按照顺序排列的对象,可以通过下表索引来存取数组中数据。跟 Python 中的 list 比较相似。
- 1#import 2 3 int main(int argc, const char * argv[]) {
- 4@autoreleasepool {
- 5 // 创建一个NSMutableArray对象,并用items变量保存该对象的地址
- 6 NSMutableArray * items = [[NSMutableArray alloc] init];
- 7 8 // 向items 所指向的NSMutableArray对象发送addObject:消息
- 9 // 每次传入一个字符串
- 10[items addObject: @"One"];
- 11[items addObject: @"Two"];
- 12[items addObject: @"Three"];
- 13 14 // 继续向同一个对象发送消息,这次是insertObject:atIndex:
- 15[items insertObject: @"Zero"atIndex: 0];
- 16 17 // 释放items 所指向的 NSMutableArray 对象
- 18 items = nil;
- 19
- }
- 20
- return 0;
- 21
- }
每次加入的对象是一个 NSString 字符串对象,可以通过 @"" 来快速创建一个字符串。
2. 遍历数组
这里我们可以直接使用 for 循环,也可以使用快速遍历。使用 for 循环的原理是:数组中下标索引是从 0 开始,到数组中最后一个对象是数组总数量 - 1.
- 1#import 2 3 int main(int argc, const char * argv[]) {
- 4@autoreleasepool {
- 5 // 创建一个NSMutableArray对象,并用items变量保存该对象的地址
- 6 NSMutableArray * items = [[NSMutableArray alloc] init];
- 7 8 // 向items 所指向的NSMutableArray对象发送addObject:消息
- 9 // 每次传入一个字符串
- 10[items addObject: @"One"];
- 11[items addObject: @"Two"];
- 12[items addObject: @"Three"];
- 13 14 // 继续向同一个对象发送消息,这次是insertObject:atIndex:
- 15[items insertObject: @"Zero"atIndex: 0];
- 16 17 // 使用for循环来遍历数组中对象
- 18
- for (NSInteger i = 0; i < items.count; i++) {
- 19 NSString * item = [items objectAtIndex: i];
- 20 NSLog(@"%@", item);
- 21
- }
- 22 23 // 释放items 所指向的 NSMutableArray 对象
- 24 items = nil;
- 25
- }
- 26
- return 0;
- 27
- }
输出结果:
- 1 2016 - 09 - 03 08 : 04 : 50.323 RandomItems[5255 : 279975] Zero 2 2016 - 09 - 03 08 : 04 : 50.324 RandomItems[5255 : 279975] One 3 2016 - 09 - 03 08 : 04 : 50.324 RandomItems[5255 : 279975] Two 4 2016 - 09 - 03 08 : 04 : 50.324 RandomItems[5255 : 279975] Three
当然,我们同样可以使用快速遍历的方法来输出结果:
- 1 // 使用快速枚举法来遍历
- 2
- for (NSString * item in items) {
- 3 NSLog(@"%@", item);
- 4
- }
这段代码同样可以工作。这种遍历数组的语法出错率更低,更重要的是经过编译器的优化,通常比 for 循环更快。在数组比较多,或者比较调用比较频繁的时候最好使用这种方法。但是有一个限制,如果需要在循环体中添加或者删除对象,那么就不能使用快速枚举方法。
现在我们来对这段代码进行简单剖析。在我们创建的 RandItems 程序中一共有 5 个对象:其中一个是 NSMutableArray 对象,4 个 NSString 对象。
在 OC 中,数组所包含的对象并不是真正的对象本身,只是指向对象的指针而已,真正的对象都是存放在堆内存中的。
1. 使用快捷键 command + N 来创建一个新的文件,之后选中 OS X -> Source 来创建一个新的文件,可以选则文件存放位置等。这里我们命名为 JXItem
2. 新创建的类文件继承至 NSObject 创建好文件之后在代码控制板中我们可以发现有两个文件: JXItem.h JXItem.m ;其中 .h 文件是头文件,也叫作接口文件,赋值声明类的类名,父类,实例变量及该类实现的全部方法; .m 文件就是一个实现文件,用来包含该 .h 文件中中声明的全部方法等。
实例变量:
实例变量就相当于我们真是世界中的 比如说你拥有的一辆汽车,汽车有品牌,颜色,价钱等固有属性;实例变量就相对于我们真是世界中的物品的属性。下面我们来声明一些实例变量。
- 1#import 2 3@interface JXItem: NSObject 4 {
- 5 NSString * _itemName;
- 6 NSString * _serialNumber;
- 7 int _valueInDollars;
- 8 NSDate * _dateCreated;
- 9
- }
- 10@end
声明了实例变量之后就相当于我们在声明每个 JXItem 对象之后都会在内存中有四个空位,用来存放我们声明的实例变量(物体的属性)。其中一个是用来存放 int 证书,另外三个用来存放指向对象的指针,分别是两个指向 NSString 对象和一个 NSDate 对象。
存取实例变量:
给对象添加了实例变量之后,我们要开始使用它,通过添加存取变量的方法,我们就可以顺利的使用这些数据,这样的方法在 OC 中我们叫做 存取方法 。如果是既可以存进去,也可以取出来的我们叫做存取方法;如果是只能读出来,但是不能存进去的我们叫做只读的,这类属性只需要取方法。
- 1#import 2 3@interface JXItem: NSObject 4 {
- 5 NSString * _itemName;
- 6 NSString * _serialNumber;
- 7 int _valueInDollars;
- 8 NSDate * _dateCreated;
- 9
- }
- 10 11 // 存方法
- 12 - (void) setItemName: (NSString * ) str;
- 13 // 取方法
- 14 - (NSString * ) itemName;
- 15 16 - (void) setSerialNumber: (NSString * ) str;
- 17 - (NSString * ) serialNumber;
- 18 19 - (void) setValueInDollars: (int) v;
- 20 - ( in ) valueInDollars;
- 21 22 - (NSDate * ) dateCreated;
- 23@end
在 OC 中,村方法的命名规则为英文 set 加上要修改的实例变量的变量名(首字母要大写)。
接下来我们开始实现存取方法。任何一个类的实现文件,都必须在顶部导入自己的头文件。类的实现需要知道响应你的类是如何声明的。在 OC 中我们使用 #import 来导入,作用和 C 语言中 #include 作用相同。唯一的差别是 #import 可以确保不会重复导入用一个文件,所以在 OC 中建议使用 #import
- 1#import "JXItem.h"2 3@implementation JXItem 4 5 - (void) setItemName: (NSString * ) str {
- 6 _itemName = str;
- 7
- }
- 8 - (NSString * ) itemName {
- 9
- return _itemName;
- 10
- }
- 11 12 - (void) setSerialNumber: (NSString * ) str {
- 13 _serialNumber = str;
- 14
- }
- 15 - (NSString * ) serialNumber {
- 16
- return _serialNumber;
- 17
- }
- 18 19 - (void) setValueInDollars: (int) v {
- 20 _valueInDollars = v;
- 21
- }
- 22 - (int) valueInDollars {
- 23
- return _valueInDollars;
- 24
- }
- 25 26 - (NSDate * ) dateCreated {
- 27
- return _dateCreated;
- 28
- }
- 29@end
在这段代码中,存方法是将传入的参数直接赋值给了实例变量,当然也可以将传入的参数进行一定的运算之后传给实例变量;取方法则就是取得是返回实例变量的值。
下面,我们开始测试新创建的类和存取方法。首先在 main.m 中导入 JXItem.h 头文件。因为 JXItem 类位于仅包含自己一个类的类文件中,所以必须要明确的导入,否则编译器编译的时候就会报错。
- 1#import 2#import "JXItem.h"3 4 int main(int argc, const char * argv[]) {
- 5@autoreleasepool {
- 6 // 创建一个NSMutableArray对象,并用items变量保存该对象的地址
- 7 NSMutableArray * items = [[NSMutableArray alloc] init];
- 8 9 // 向items 所指向的NSMutableArray对象发送addObject:消息
- 10 // 每次传入一个字符串
- 11[items addObject: @"One"];
- 12[items addObject: @"Two"];
- 13[items addObject: @"Three"];
- 14 15 // 继续向同一个对象发送消息,这次是insertObject:atIndex:
- 16[items insertObject: @"Zero"atIndex: 0];
- 17 18 // 使用快速枚举法来遍历
- 19
- for (NSString * item in items) {
- 20 NSLog(@"%@", item);
- 21
- }
- 22 23 JXItem * item = [[JXItem alloc] init];
- 24 NSLog(@"%@ %@ %@ %d", item.itemName, item.dateCreated, item.serialNumber, item.valueInDollars);
- 25 26 // 释放items 所指向的 NSMutableArray 对象
- 27 items = nil;
- 28
- }
- 29
- return 0;
- 30
- }
打印结果:
- 1 2016 - 09 - 04 08 : 31 : 50.302 RandomItems[9471 : 742805] Zero 2 2016 - 09 - 04 08 : 31 : 50.303 RandomItems[9471 : 742805] One 3 2016 - 09 - 04 08 : 31 : 50.303 RandomItems[9471 : 742805] Two 4 2016 - 09 - 04 08 : 31 : 50.303 RandomItems[9471 : 742805] Three 5 2016 - 09 - 04 08 : 31 : 50.303 RandomItems[9471 : 742805](null)(null)(null) 0 6 Program ended with exit code: 0
可以看到现在我们仅仅初始化了我们创建的类,并没有将之赋值,所以的实例变量都是默认值。因为当实例变量是指向对象的指针,那么相应的初始值为 nil;而如果实例变量是 int 这样的基本类型,那么其值就会是 0 。
下面,我们为新创建的对象设置一些有意义的值。
- 1#import 2#import "JXItem.h"3 4 int main(int argc, const char * argv[]) {
- 5@autoreleasepool {
- 6 // 创建一个NSMutableArray对象,并用items变量保存该对象的地址
- 7 NSMutableArray * items = [[NSMutableArray alloc] init];
- 8 9 // 向items 所指向的NSMutableArray对象发送addObject:消息
- 10 // 每次传入一个字符串
- 11[items addObject: @"One"];
- 12[items addObject: @"Two"];
- 13[items addObject: @"Three"];
- 14 15 // 继续向同一个对象发送消息,这次是insertObject:atIndex:
- 16[items insertObject: @"Zero"atIndex: 0];
- 17 18 // 使用快速枚举法来遍历
- 19
- for (NSString * item in items) {
- 20 NSLog(@"%@", item);
- 21
- }
- 22 23 JXItem * item = [[JXItem alloc] init];
- 24 item.itemName = @"Ferrari";
- 25 item.serialNumber = @"PC23138";
- 26 item.valueInDollars = 783234;
- 27 NSLog(@"%@ %@ %@ %d", item.itemName, item.dateCreated, item.serialNumber, item.valueInDollars);
- 28 29 // 释放items 所指向的 NSMutableArray 对象
- 30 items = nil;
- 31
- }
- 32
- return 0;
- 33
- }
打印结果:
- 1 2016 - 09 - 04 08 : 41 : 44.566 RandomItems[9554 : 749674] Zero 2 2016 - 09 - 04 08 : 41 : 44.567 RandomItems[9554 : 749674] One 3 2016 - 09 - 04 08 : 41 : 44.567 RandomItems[9554 : 749674] Two 4 2016 - 09 - 04 08 : 41 : 44.567 RandomItems[9554 : 749674] Three 5 2016 - 09 - 04 08 : 41 : 44.567 RandomItems[9554 : 749674] Ferrari(null) PC23138 783234 6 Program ended with exit code: 0
解释:有些人可能会纳闷,这里我们并没有调用 set 方法来给我们自定义的类的实例变量来赋值,为什么这里就可以打印出来了。这是因为我们这里使用了点语法。 点语法的格式为:消息接受者(item)后面加上一个 "." ,在加上实例变量的名字。这样子就可以取代我们的 set 方法。值得注意的是,点语法虽然很方便,但是会经常给我们造成困扰,你会发现点语法放在等号的左边和右边效果是不一样的。他们的区别是:如果点语法用在赋值号的左边,就表示存方法(set 方法);如果在右边就代表是取方法。
类方法和实例方法
在 OC 中,方法可以分为类方法和实例方法。
类方法的作用通常是创建一个对象,获取类的某些全局的属性。类方法不会创建到对象上,也不会存取实例变量。类就好比是一个法拉利工作,对象就是一台法拉利。工厂只会有一些生产规划时间等,而某个法拉利自身的属性,比如说是创建时间,只有他自己知道,工厂只能知道在一段时间内有多少台法拉利被生产。
实例变量方法:用来操作类的对象。
当我们调用实例方法时,需要向类的对象发送消息;调用类方法时,只需要向类本身发送消息。
例如,我们在创建 JXItem 对象的时候,首先向 JXItem 类发送 alloc (类方法)消息,然后使用 alloc 方法创建的对象发送 init (实例方法)消息。
覆盖方法
子类可以覆盖父类的方法。我们这里以 description 为例,向某个 NSObject 对象发送 description 消息是,可以得到一个 NSString 对象来描述当当前对象的类名和其在内存中的地址信息。通常格式为 0x1002042b0> 。 下面我们来尝试覆盖整个方法,来自定义。
- 1#import "JXItem.h"2 3@implementation JXItem 4 5 - (void) setItemName: (NSString * ) str {
- 6 _itemName = str;
- 7
- }
- 8 - (NSString * ) itemName {
- 9
- return _itemName;
- 10
- }
- 11 12 - (void) setSerialNumber: (NSString * ) str {
- 13 _serialNumber = str;
- 14
- }
- 15 - (NSString * ) serialNumber {
- 16
- return _serialNumber;
- 17
- }
- 18 19 - (void) setValueInDollars: (int) v {
- 20 _valueInDollars = v;
- 21
- }
- 22 - (int) valueInDollars {
- 23
- return _valueInDollars;
- 24
- }
- 25 26 - (NSDate * ) dateCreated {
- 27
- return _dateCreated;
- 28
- }
- 29 30 - (NSString * ) description {
- 31 NSString * descriptionString = [[NSString alloc] initWithFormat: @"%@ (%@): Worth $%d,recorded on %@", self.itemName, self.serialNumber, self.valueInDollars, self.dateCreated];
- 32
- return descriptionString;
- 33
- }
- 34@end
调用方法:
- 1#import 2#import "JXItem.h"3 4 int main(int argc, const char * argv[]) {
- 5@autoreleasepool {
- 6 // 创建一个NSMutableArray对象,并用items变量保存该对象的地址
- 7 NSMutableArray * items = [[NSMutableArray alloc] init];
- 8 9 // 向items 所指向的NSMutableArray对象发送addObject:消息
- 10 // 每次传入一个字符串
- 11[items addObject: @"One"];
- 12[items addObject: @"Two"];
- 13[items addObject: @"Three"];
- 14 15 // 继续向同一个对象发送消息,这次是insertObject:atIndex:
- 16[items insertObject: @"Zero"atIndex: 0];
- 17 18 // 使用快速枚举法来遍历
- 19
- for (NSString * item in items) {
- 20 NSLog(@"%@", item);
- 21
- }
- 22 23 JXItem * item = [[JXItem alloc] init];
- 24 item.itemName = @"Ferrari";
- 25 item.serialNumber = @"PC23138";
- 26 item.valueInDollars = 783234;
- 27 NSLog(@"%@", item);
- 28 29 // 释放items 所指向的 NSMutableArray 对象
- 30 items = nil;
- 31
- }
- 32
- return 0;
- 33
- }
打印结果:
- 1 2016 - 09 - 04 09 : 16 : 59.595 RandomItems[9666 : 763580] Zero 2 2016 - 09 - 04 09 : 16 : 59.596 RandomItems[9666 : 763580] One 3 2016 - 09 - 04 09 : 16 : 59.596 RandomItems[9666 : 763580] Two 4 2016 - 09 - 04 09 : 16 : 59.596 RandomItems[9666 : 763580] Three 5 2016 - 09 - 04 09 : 16 : 59.596 RandomItems[9666 : 763580] Ferrari(PC23138) : Worth $783234,
- recorded on(null)
解释:当我们在程序中调用 NSLog(@"%@",item); 这句话会首先调用 description 方法。
我们创建的 JXItem 目前还只能充 NSObject 类继承来的 init 方法来初始化对象。现在我们就来创建两个新的实例方法用于初始化对象;这种用于初始化类的对象的方法我们称之为初始化方法。
- 1#import 2 3@interface JXItem: NSObject 4 {
- 5 NSString * _itemName;
- 6 NSString * _serialNumber;
- 7 int _valueInDollars;
- 8 NSDate * _dateCreated;
- 9
- }
- 10 11 // 初始化方法
- 12 - (instancetype) initWithItemName: (NSString * ) name 13 valueInDollars: (int) value 14 serialNumber: (NSString * ) sNumber;
- 15 16 - (instancetype) initWithItemName: (NSString * ) name;
- 17 // 存方法
- 18 - (void) setItemName: (NSString * ) str;
- 19 // 取方法
- 20 - (NSString * ) itemName;
- 21 22 - (void) setSerialNumber: (NSString * ) str;
- 23 - (NSString * ) serialNumber;
- 24 25 - (void) setValueInDollars: (int) v;
- 26 - (int) valueInDollars;
- 27 28 - (NSDate * ) dateCreated;
- 29@end
每个初始化方法的方法名都会以 init 开头。这种初始化方法的命名模式只是一种约定,但是在 OC 中我们应该严格遵守这种约定。这类自定义的初始化方法一般都会带有参数,为的就是应付各种不同的初始化需要。
任何一个类,不管有多少个初始化方法,都必须选定其中一个作为 指定初始化 方法。
instancetype
上面我们创建的两个初始化方法的返回值类型都是 instancetype 。该关键字表示方法的返回类型个调用方法的对象类型相同。 init 方法的返回类型都应该声明为 instancetype 。这里可能会有疑问,为什么我们不反悔这个类本身的类型呢?这是因为我们有可能会继续写一个类来继承这个类,由于子类可以继承父类的方法,其中包括初始化方法和返回类型。如果是这个类的子类调用初始化方法,那么返回同样是这个类对象,而不是这个类的子类对象。所以为了避免这个问题,我们使用 instancetype 来动态获取当前类对象。
实现 JXItem 类的指定初始化方法
在 JXItem.m 中为该类实现指定初始化方法
- 1#import "JXItem.h"2 3@implementation JXItem 4 - (instancetype) initWithItemName: (NSString * ) name 5 valueInDollars: (int) value 6 serialNumber: (NSString * ) sNumber {
- 7 // 调用父类的初始化方法
- 8 self = [super init];
- 9 10 // 判断父类的指定初始化方法是否是成功创建
- 11
- if (self) {
- 12 // 为实例变量设置初始值
- 13 _itemName = name;
- 14 _serialNumber = sNumber;
- 15 _valueInDollars = value;
- 16 17 // 设置 _dateCreated 的值为系统当前时间
- 18 // 因为我们没有为该实例变量设置 set 方法来从外部获取 (只是一个只读属性)
- 19 _dateCreated = [NSDate date];
- 20
- }
- 21 // 返回初始化后的对象的新地址
- 22
- return self;
- 23 24
- }
- 25 26 - (void) setItemName: (NSString * ) str {
- 27 _itemName = str;
- 28
- }
- 29 - (NSString * ) itemName {
- 30
- return _itemName;
- 31
- }
- 32 33 - (void) setSerialNumber: (NSString * ) str {
- 34 _serialNumber = str;
- 35
- }
- 36 - (NSString * ) serialNumber {
- 37
- return _serialNumber;
- 38
- }
- 39 40 - (void) setValueInDollars: (int) v {
- 41 _valueInDollars = v;
- 42
- }
- 43 - (int) valueInDollars {
- 44
- return _valueInDollars;
- 45
- }
- 46 47 - (NSDate * ) dateCreated {
- 48
- return _dateCreated;
- 49
- }
- 50 51 - (NSString * ) description {
- 52 NSString * descriptionString = [[NSString alloc] initWithFormat: @"%@ (%@): Worth $%d,recorded on %@", self.itemName, self.serialNumber, self.valueInDollars, self.dateCreated];
- 53
- return descriptionString;
- 54
- }
- 55@end
初始化方法中的实例变量
在自定义的初始化方法中我们可以看到有在初始化实例变量。但是在 OC 中有个雷区就是千万不要直接访问实例变量,最好直接通过存取方法来访问。但是这个雷区在初始化方法总相反,我们要直接访问实例变量
其他初始化方法与初始化方法链
接下来我们来实现第二个初始化方法。实现 initWithItemName:(NSString *)name 方法时,我们不需要再将其他初始化方法搬过来重新写一遍。这里我们只需要调用一下其他指定初始化方法,将我们获取到的实参作为 _itemName 传入,其他的实参则使用某个默认值传入。
JXItem 还有一个默认的初始化方法 init 。如果我们直接向对象发送这个消息,那么程序就不会调用我们自定义的初始化方法,辛苦白费了。当然了,我们是不会让这种情况发生的。
- 1#import "JXItem.h"2 3@implementation JXItem 4 - (instancetype) initWithItemName: (NSString * ) name 5 valueInDollars: (int) value 6 serialNumber: (NSString * ) sNumber {
- 7 // 调用父类的初始化方法
- 8 self = [super init];
- 9 10 // 判断父类的指定初始化方法是否是成功创建
- 11
- if (self) {
- 12 // 为实例变量设置初始值
- 13 _itemName = name;
- 14 _serialNumber = sNumber;
- 15 _valueInDollars = value;
- 16 17 // 设置 _dateCreated 的值为系统当前时间
- 18 // 因为我们没有为该实例变量设置 set 方法来从外部获取 (只是一个只读属性)
- 19 _dateCreated = [NSDate date];
- 20
- }
- 21 // 返回初始化后的对象的新地址
- 22
- return self;
- 23 24
- }
- 25 26 - (instancetype) initWithItemName: (NSString * ) name {
- 27
- return [self initWithItemName: name 28 valueInDollars: 0 29 serialNumber: @""];
- 30
- }
- 31 32 // 默认的初始化方法,调用自定义的初始化方法,并将之出入一个默认值
- 33 - (instancetype) init {
- 34
- return [self initWithItemName: @"Item"];
- 35
- }
- 36 37 - (void) setItemName: (NSString * ) str {
- 38 _itemName = str;
- 39
- }
- 40 - (NSString * ) itemName {
- 41
- return _itemName;
- 42
- }
- 43 44 - (void) setSerialNumber: (NSString * ) str {
- 45 _serialNumber = str;
- 46
- }
- 47 - (NSString * ) serialNumber {
- 48
- return _serialNumber;
- 49
- }
- 50 51 - (void) setValueInDollars: (int) v {
- 52 _valueInDollars = v;
- 53
- }
- 54 - (int) valueInDollars {
- 55
- return _valueInDollars;
- 56
- }
- 57 58 - (NSDate * ) dateCreated {
- 59
- return _dateCreated;
- 60
- }
- 61 62 - (NSString * ) description {
- 63 NSString * descriptionString = [[NSString alloc] initWithFormat: @"%@ (%@): Worth $%d,recorded on %@", self.itemName, self.serialNumber, self.valueInDollars, self.dateCreated];
- 64
- return descriptionString;
- 65
- }
- 66@end
下面我们来观察一下初始化之间的关系
串联使用初始化方法的机制可以减少错误,也可以更加容易的维护代码。在创建类时,需要先确定指定初始,然后只在指定的初始化方法中编写核心代码,其他初始化方法只需要调用指定初始化方法(直接或间接)并传入默认值即可。
下面为初始化方法总结一些简单规则:
1. 类会集成父类所有的方法,包括初始化方法,也可以为类加入任意数量的初始化方法
2. 每个类都要选定一个初始化方法
3. 在执行其他初始化工作之前,必须先用指定初始化方法调用父类的指定初始化方法(一般为直接调用 [super init] )
4. 如果某个类所声明的指定初始化方法与其父类的不同,就必须覆盖父类的指定初始化方法,并调用新的指定的初始化方法
使用初始化方法
- 1#import 2#import "JXItem.h"3 4 int main(int argc, const char * argv[]) {
- 5@autoreleasepool {
- 6 // 创建一个NSMutableArray对象,并用items变量保存该对象的地址
- 7 NSMutableArray * items = [[NSMutableArray alloc] init];
- 8 9 // 向items 所指向的NSMutableArray对象发送addObject:消息
- 10 // 每次传入一个字符串
- 11[items addObject: @"One"];
- 12[items addObject: @"Two"];
- 13[items addObject: @"Three"];
- 14 15 // 继续向同一个对象发送消息,这次是insertObject:atIndex:
- 16[items insertObject: @"Zero"atIndex: 0];
- 17 18 // 使用快速枚举法来遍历
- 19
- for (NSString * item in items) {
- 20 NSLog(@"%@", item);
- 21
- }
- 22 23 JXItem * item = [[JXItem alloc] initWithItemName: @"Ferrari"valueInDollars: 783234 serialNumber: @"PC23138"];
- 24 NSLog(@"%@", item);
- 25 26 // 释放items 所指向的 NSMutableArray 对象
- 27 items = nil;
- 28
- }
- 29
- return 0;
- 30
- }
运行结果:
- 1 2016 - 09 - 04 10 : 33 : 33.600 RandomItems[9893 : 797491] Zero 2 2016 - 09 - 04 10 : 33 : 33.600 RandomItems[9893 : 797491] One 3 2016 - 09 - 04 10 : 33 : 33.600 RandomItems[9893 : 797491] Two 4 2016 - 09 - 04 10 : 33 : 33.601 RandomItems[9893 : 797491] Three 5 2016 - 09 - 04 10 : 33 : 33.608 RandomItems[9893 : 797491] Ferrari(PC23138) : Worth $783234,
- recorded on 2016 - 09 - 04 02 : 33 : 33 + 0000 6 Program ended with exit code: 0
在运行的时候,当某个对象收到消息后,会根据创建该对象的类,执行和相应的消息匹配的方法。这种特性和多数编译语
来源: http://www.cnblogs.com/wang-com/p/5824321.html