第8条:对象等同性概念。
NSObject协议中声明的isEqual,用于判断两个对象的等同性。某些特定类️特殊的方法判断对象等同性,如NSString的isEqualToString。==表示指针指向同一对象,isEqual一般表示指针值相等,复杂的类若有需要可覆写该方法。
若两个对象等同,其哈希码hash也相等,但hash相等两个对象未必等同。hash在集合中,检索哈希表(hash table)时,会用对象的哈希码做索引,比如set,可能会根据hash把对象分配到不同的数组,添加新对象时,回根据hash找到对应数组,依次检测数组中是否有相同的对象。因此若要重写hash,既要减少碰撞(collision),保持效率,也要控制hash在一定范围内,降低复杂度。
NSArray用isEqualToArray来判断对象等同性,而NSDictionary则使用isEqualToDictionary。由于Objective-C在编译期不做强制类型检查(strong type check),开发者应保证对象类型正确。
对象等同性执行深度取决于受测对象的实际情况。
把可变容器放入集合需要注意消除元素相等的隐患,一般不建议这么做。如一个集合添加了两个不同的可变数组,集合此时有两个不同的元素,而当一个可变数组改成与另外一个相等时,则会造成集合中有两个等同的数组,有可能不符合需要。
第9条:以类族模式隐藏实现细节。
类族(class cluster)模式(pattern),可以隐藏抽象基类(abstract base class)的实现细节,Objective-C系统框架普遍使用此模式。如UIKit(user interface framework)中UIButton创建按钮可用类方法buttonWithType,返回的对象取决于传人的类型,UIButton据此创建不同的对象。优秀的程序员会重构不同的子类,将它们的实现细节隐藏在抽象基类后面,使用者一般不需要知道子类细节。
大部分容器是类族,如NSArray和NSMutableArray。实例方法isKindOfClass可检测是否位于类族中。
第10条:在既有类中使用关联对象存放自定义数据。
一般在一个类中存放自定义数据的做法是继承这个类。而一些特殊的机制下可能难以这么做,例如引入第三方库创建的对象可能是固定的类型,难以替换成子类。Objective-C的关联对象(Associated Object)可解决此问题。一个类对象可通过键关联其他对象,并指明存储策略(storage policy),维护内存管理语义。
关联类型与属性对应关系如下:
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic,retain
OBJC_ASSOCIATION_COPY_NONATOMIC nonatomic,copy
OBJC_ASSOCIATION_RETAIN retain
OBJC_ASSOCIATION_COPY copy
objc_setAssociatedObject是关联方法。
objc_getAssociatedObject是获取方法。
objc_removeAssociatedObjects是移除方法。
关联方法很有用,但不能滥用,应优先选择其他方法,如继承。