Objective-C 对象(内容根据iOS编程编写)

Posted rookieJX

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Objective-C 对象(内容根据iOS编程编写)相关的知识,希望对你有一定的参考价值。

  开发ios程序需要使用 Objective-C 语言和Cocoa Touch框架。Objective-C 源于 C 语言,是 C 语言的扩展。 Cocoa Touch框架是一个Objective-C类的集合。本篇文章用来介绍一些Objective-C基础知识。

  •   对象

  假设有一场聚会。该聚会有若干特有的属性,例如聚会的名称,日期和一根受邀请的名单。此外,还有“聚会”需要做些事情,比如向受邀请者发送一封提醒邮件,或者取消聚会。

  如果使用C语言,那么我们可以定义一个 结构体 ,用于保存这场聚会的数据类型。

  如果使用 Objective-C 来定义这些数据类型,我们就需要用到 类 。 类就像是制造汽车的工厂,通过工厂(类:聚会)我们可以制造汽车(具体的某一场特性的聚会),这些汽车都是工厂的的实例,每个实例对象都能为某一个特定的聚会保存数据。

  所有的对象,都是在内存中的一块数据,类似于结构体。对象要通过实例变量保存属性(例如:汽车的颜色,形状,型号。聚会的名称,等都是属性)。在  Objective-C 中实例变量名之前通常会加上一个下划线。因此,我们的 Party 对象定义实例变量: _name(名称),_date(日期),_budget(预算) 图1-1:Party类及其对象

  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 发送消息。

  • 编写第一个命令行工具 RandomItems

选择Xcode,进入命令行工具,RandomItems的第一个版本将创建一个包含4个字符串的数组。 数组 包含一组按照顺序排列的对象,可以通过下表索引来存取数组中数据。跟 Python 中的 list 比较相似。

  1. 创建数组,并填充字符串
 1 #import <Foundation/Foundation.h>
 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 <Foundation/Foundation.h>
 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 对象。

RandItems程序对象解析

  在OC中,数组所包含的对象并不是真正的对象本身,只是指向对象的指针而已,真正的对象都是存放在堆内存中的。

  • 创建Objective-C类的子类

1. 使用快捷键  command + N  来创建一个新的文件,之后选中 OS X -> Source来创建一个新的文件,可以选则文件存放位置等。这里我们命名为 JXItem

2. 新创建的类文件继承至  NSObject 创建好文件之后在代码控制板中我们可以发现有两个文件: JXItem.h  JXItem.m ;其中 .h 文件是头文件,也叫作接口文件,赋值声明类的类名,父类,实例变量及该类实现的全部方法; .m 文件就是一个实现文件,用来包含该 .h文件中中声明的全部方法等。

  实例变量:

  实例变量就相当于我们真是世界中的 比如说你拥有的一辆汽车,汽车有品牌,颜色,价钱等固有属性;实例变量就相对于我们真是世界中的物品的属性。下面我们来声明一些实例变量。

 1 #import <Foundation/Foundation.h>
 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 <Foundation/Foundation.h>
 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 <Foundation/Foundation.h>
 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 <Foundation/Foundation.h>
 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 对象来描述当当前对象的类名和其在内存中的地址信息。通常格式为  <JXItem: 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 <Foundation/Foundation.h>
 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 方法来初始化对象。现在我们就来创建两个新的实例方法用于初始化对象;这种用于初始化类的对象的方法我们称之为初始化方法。