Effective Objective-C 2.0 笔记2

二、对象、消息和运行时

①、直接访问实例变量还是使用属性方法访问?

(1)、直接访问实例变量速度快,因为不经过Objective-C的方法分发系统,而是直接用的变量在内存中的存储地址。

(2)、同时,直接访问会忽视属性property的内存管理语法。例如,如果一个属性定义为copy,直接访问就会忽视copy,不会产生一个复制。

(3)、直接访问实例变量,不会出发KVO通知。因为KVO是改写了别观察属性的set方法,在变化前和变化后,发送通知。具体文章可以猛击这里。一个妥协的解决方案是,读数据时采用直接访问方式,写数据时采用属性方法setXXX方式。这样,既可以保证读取速度,又能保证写数据时的内存管理策略的正确性。

(4)、在initializers和dealloc等方法中,用直接访问的方式来读、写实例变量。

(5)、当属性是懒加载模式时,需要用属性方法getXXX来读取。

1
2
3
4
5
6
- (NSString *)name {
if (!_name) {
_name = @"测试名字";
}
return _name;
}

②、对象相等,必须有相同的hash值。拥有相同hash值的对象,不必相等。

③、类簇模式是抽象工厂模式的一种。

④、消息转发

(1)、编译器会把方法转成一个标准的C函数void objc_msgSend(id self,SEL cmd,…),其中第一个参数是接收者,第二个参数是selector,即方法。

(2)、方法调用的过程:首先,会在类的方法列表中查找方法。如果找不到,则从继承链上的父类方法中查找。如果还找不到,则进行消息转发。

(3)、objc_msgSend会缓存已经用过的方法,以方便以后快速调用。即使如此缓存,还是比静态绑定慢。实际情况中,消息分发系统不是应用速度的瓶颈所在。

(4)、消息转发示意图



其中每一步消息接收者都有一次机会来处理消息。越往后,所花费的开销就越大。

(5)、从集合类中取出元素的时候,会用到Objective-C的内省方法。因为取出的元素不是强类型,通常是id类型。在编译时,对象的类型是未知的,就需要使用内省方法。比较对象时,要用内省方法,而不是直接比较。因为对象可能实现了消息转发。例如,NSProxy。