对象,消息,运行期

Thursday, January 4, 2018

理解属性

  • 阻止编译器自动合成存取方法,就是使用@dynamic 关键字,一般使用 CoreData 框架会使用该关键字
  • 属性特性
    • 原子性(atomicity),默认合成方法会确保原子性,如果具备 nonatomic,则不使用同步锁。
    • 读写权限,readwrite 和 readonly
    • assign,针对纯量类型
    • strong,表示拥有关系,先保留新值,并释放旧值。
    • weak,非拥有关系,既不保留新值,也不释放旧值,属性所指的对象遭到摧毁时,属性值也会清空(nil)。
    • unsafe_unretained,与 assign 相同,但适用于对象类型,目标对象遭到摧毁时,属性值不会自动清空,这是跟 weak 的区别。
    • copy,与 strong 类似,但是并不保留新值,而是将其 copy。常用在 NSString 上。
  • iOS 开发一般都用 nonatomic,因为在 iOS 中使用同步锁开销较大。若要实现线程安全,还需要更为深层的锁定机制才行。

在对象内部尽量直接访问实例变量

  • 由于不经过 method dispatch,所以直接访问实例变量会比较快。
  • 直接访问实例变量,不会调用设置方法。比如声明了 copy 属性,那么并不会拷贝该属性,而是保留新值,释放旧值。
  • 直接访问实例变量,不会触发 KVO。
  • 通过属性访问有助于排查与之相关的错误。因为可以给设置方法和读取方法里新增断点。
  • 最佳实践:写入实例变量时,通过设置方法来做,而在读取实例变量,则直接访问。
  • 初始化设置属性值时,总是应该直接访问实例变量,因为子类可能会覆写设置方法。
  • 如果使用了惰性初始化,则必须要通过读取方法来读取数据。

理解『对象等同性』

  • 按照==操作符比较出来的结果未必是我们想要的,因为该操作比较的是两个指针的本身,而不是对应的数据。
- (BOOL)isEqual:(id)object;
- (NSUInteger)hash;
  • 系统的默认实现是,当且仅当指针值完全相等,这两个对象才相等。如果『isEqual』方法判定两个对象相等,那么其 hash 方法也必须返回同一个值,但是,如果两个对象 hash 方法返回同一个值,那么『isEqual』未必认为两者相等。
  • 重写 isEqual 方法
@property(nonatomic, copy) NSString *firstName;
@property(nonatomic, copy) NSString *lastName;
- (BOOL)isEqual:(id)object {
        if (self == object) return YES;
        if ([self class] != [object class]) return NO;
        EOCPerson *otherPerson = (EOCPerson *)object;
        if (![_firstName isEqualToString: otherPerson.firstName])
        return NO;
        if (![_lastName isEqualToString:otherPerson.lastName])
        return NO;
        return YES;
}
  • hash 方法
- (NSUInteger)hash {
        NSUInteger firstNameHash = [_firstName hash];
        NSUInteger lastNameHash = [_lastName hash];
        NSUInteger ageHash = _age;
        return fistNameHash ^ lastNameHash ^ ageHash;
}
  • 如果经常需要判断等同性,那么可以创建自己的等同性判定方法。
  • 在编写判定方法时,也应一并覆写『isEqual』方法,如果两个对象都属于同一个类,那么就调用自己的判定方法,否则就给超类判定。

等同判定的执行深度

  • NSArray 的检测方式为先看两个数组所含对象个数是否相同,若相同,则在每个对应的两个对象调用 isEqual 方法。如果都相等,这叫做『深度等同性判定』
Objective-C

运行期(runtime)

熟悉 Objective-C