内存管理语义
属性用于封装数据,而数据则要有“具体的所有权语义”(concrete ownership semantic)。下面这一组特质仅会影响“设置方法”。例如,用“设置方法”设定一个新值时,它是应该“保留”(retain)”此值呢,还是只将其赋给底层实例变量就好?编译器在合成存取方法时,要根据此特质来决定所生成的代码。如果自己编写存取方法,那么就必须同有关属性所具备的特质相符。
assign“设置方法”只会执行针对“纯量类型”(scalar type,例如 CGFloat 或NSInteger 等)的简单赋值操作。
strong 此特质表明该属性定义了一种“拥有关系”(owning relationship)。为这种属性设置新值时,设置方法会先保留新值,并释放旧值,然后再将新值设置上去。
weak 此特质表明该属性定义了一种“非拥有关系”(nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同 assign 类似,然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。
unsafe unretained 此特质的语义和 assign 相同,但是它适用于“对象类型”(object type),该特质表达一种“非拥有关系”(“不保留”,unretained),当目标对象遭到摧毁时,属性值不会自动清空(“不安全”,unsafe),这一点与 weak 有区别。
copy 此特质所表达的所属关系与 strong 类似。然而设置方法并不保留新值,而是将其“拷贝”(copy)。当属性类型为 NSString*时,经常用此特质来保护其封装性,因为传递给设置方祛的新值有可能指向一个 NSMutableString 类的实例。这个类是 NSString 的子类,表示- ~种可以修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变”(immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的”(mutable),就应该在设置新属性值时拷贝一份。
第11条讲解了对象的消息传递机制,并强调了其重要性。第12条则要讲解另外-一个重
要的问题,就是对象在收到无法解读的消息之后会发生什么情况。
若想令类能理解某条消息,我们必须以程序码实现出对应的方法才行。但是,在编译
期向类发送了其无法解读的消息并不会报错,因为在运行期可以继续向类中添加方法,所以
编译器在编译时还无法确知类中到底会不会有某个方法实现。当对象接收到无法解读的消息
后,就会启动“消息转发”( message forwarding)机制,程序员可经由此过程告诉对象应该如
何处理未知消息。
你可能早就遇到过经由消息转发流程所处理的消息了,只是未加留意。如果在控制台中
看到下面这种提示信息,那就说明你曾向某个对象发送过一条其无法解读的消息,从而启动
了消息转发机制,并将此消息转发给了NSObject 的默认实现。
-[___ NSCFNumber lowercaseString]: unrecognized selector sent to
instance 0x87
*** Terminating app due to uncaught exception
'NSInval idArgumentException', reason:
'-[__ NSCFNumber
lowe rcaseString] ; unrecognized selector sent to instance 0x87 '
上面这段异常信息是由NSObject的“doesNotRecognizeSelector:'
方法所抛出的,此异常表明:消息接收者的类型是___ NSCFNumber, 而该接收者无法理解名为lowercaseString
的选择子。本例所列举的这种情况并不奇怪,因为NSNumber类里本来就没有名为
lowercaseString的方法。控制台中看到的那个__ NSFCNumber 是为了实现“无缝桥接”(toll-free
bridging,第49条将会详解此技术)而使用的内部类(intermal class), 配置NSNumber对象时
也会- -并创建此对象。在本例中,消息转发过程以应用程序崩溃而告终,不过,开发者在编
写自己的类时,可于转发过程中设置挂钩,用以执行预定的逻辑,而不使应用程序崩溃。
第49条:对自定义其内存管理语义的collection使用无缝桥接
简单的无缝桥接
image.png QQ截图20180925133731.png
网友评论