3.4 对象
3.4.1 创建对象
对象是类Class运行时的实例,它包含了自己的实例变量(属性中声明)的内存副本以及类方法的指针,在实际开发中可以采用分配内存地址alloc以及初始化init两个步骤来创建一个对象。
对象的创建分为两个阶段:内存空间分配和初始化。通常情况下,初始化总是紧跟在内存空间分配之后进行的,但是在创建对象的过程中,这两个操作的作用是不同的。
1.分配内存空间alloc
在为一个对象分配内存空间时,需要调用alloc或者allocWithZone:方法。
除了为对象在程序的内存区划定一块合适大小的内存空间之外,alloc方法还有以下几个重要作用:
- 将对象的引用计数(ReferenceCount)设置为1。其中,引用计数与对象的内存管理有关,在ARC模式下,当引用计数为0时,对象会被释放。
- 初始化对象的isa指针并指向对象的类。在实际开发过程中,会遇到对象类和类对象两个概念,其中,对象类是一个根据类定义编译得到的运行对象。另外,每一个对象都有一个isa指针标识其是哪个类的实例。
- 将类中定义的属性(实例变量)的值初始化为0或者nil。
如下方的示例代码,创建了一个MYClass类的对象,只执行了alloc操作,在内存中分配了内存空间,但未进行任何初始化操作。打印了这个对象的地址是存在的,但是其name属性的值为空。
运行结果如图3-11所示。
图3-11 运行结果
2.初始化init
初始化的过程将对象的实例变量设置为合理且有用的初始值,还可以分配和准备对象需要的其他全局资源,并在必要时加载诸如文件这样的资源。初始化方法一般都以init开头,可以设置多个初始化的方法,例如,NSString类提供了如下初始化方法:
以init方法为例,在对象调用init方法时,主要完成了以下工作:
- 调用父类的初始化方法[super init];。
- 如果父类返回的对象不为空,则可以对对象进行进一步的设置;例如,在一个自定义UIView类中,可以设置该类的backgroundColor属性。
- 如果父类返回的对象为nil,则直接返回nil。
3.类方法
类方法是方法前面为+号的方法,类方法把创建对象过程中的两个步骤(内存空间分配+初始化)合并,直接返回被创建的对象。在实际开发过程中,类方法的使用非常普遍,例如,NSString类也提供了如下类方法:
下方的示例代码中分别使用类方法和实例方法创建了NSString类型的对象,并打印出字符串的内容。
运行结果如图3-12所示。
图3-12 运行结果
3.4.2 对象操作
针对对象的常见操作主要包括:判断对象的类型、判断对象是否响应消息、对象间的比较以及对象复制。
1.判断对象的类型
对象通过调用isKindOfClass:方法,可以判断对象的类型。isKindOfClass:方法是NSObject类的方法,将类型为Class的对象aClass作为参数传入,返回一个BOOL类型的返回值。
例如,下面的代码用来判断对象str是否为NSString类型,如果是NSString类型,则打印一段日志。
运行结果如图3-13所示。
图3-13 运行结果
另外,isKindOfClass:方法还可以用于判断子类对象的类型,如下面的代码所示,NSMutableString是NSString的子类,代码执行后,isKindOfClass:方法会认定mutableStr对象也是属于NSString类型。
运行结果如图3-14所示。
图3-14 运行结果
2.判断对象是否响应消息
在Objective-C中,调用对象的方法需要向对象发送消息,这是Objective-C语言的重要特征。要判断一个对象是否响应一条消息,则可以调用respondsToSelector:方法。应用程序通常在验证一个对象响应一则消息后,才将消息发送给该对象。
这种机制常常用于代理中,先判断代理对象是否响应代理方法,如果响应,则代表代理对象中已经实现了代理方法,然后再通知代理对象执行代理方法。
在下方的示例代码中演示了respondsToSelector:方法的使用方法。
- 在自定义类MYClass.h文件中,添加一个name属性。
- 在自定义类MYClass.m文件中,对属性进行懒加载(getter方法)。
- 在main()中,判断自定义类是否实现了属性的getter方法。
运行结果如图3-15所示。
图3-15 运行结果
3.对象间的比较
当需要对比两个对象是否相同时,可以使用isEqual:方法。如果相同,则该方法返回YES。该方法是在NSObject类中定义的,因此所有的对象都可以调用这个方法。另外,在最常用的Foundation框架中,也提供了isEqualToString:或者isEqualToDictionary:等方法,在实际开发中使用更加广泛一些。
下方的示例代码中,对字符串进行了比较操作,使用了isEqual:方法以及isEqualToString:方法。
运行结果如图3-16所示。
图3-16 运行结果
4.对象复制
通过调用copy方法,可以创建对象的副本。调用copy方法,有个前提条件,即接收的对象的类必须遵守NSCopying协议。另外,在使用对象复制时,还需要考虑针对该对象是深复制(对象复制),还是浅复制(指针复制),有关深复制与浅复制后续会详细介绍。
下面的示例代码中,由于NSString类在定义中遵守了NSCopying协议,因此可以对NSString类型的字符串对象进行复制。
运行结果如图3-17所示。
图3-17 运行结果