iOS:self.xx vs self->_xx vs _xx

基本理解

  • self.xx 是对类的属性访问,会调用getter、setter方法;
  • _xx 是直接对实例变量的操作;
  • _xx 类似于 self->_xx(类外肯定没法用 _xx,但 self->_xx 还是有想象空间的)。
  • 所有被声明为属性的成员,在iOS5 之前需要使用编译器指令@synthesize 来告诉编译器帮助生成属性的getter,setter方法。之后这个指令可以不用人为指定了,默认情况下编译器会帮我们生成。
  • 编译器在生成getter,setter方法时是有优先级的,它首先查找当前的类中用户是否已定义属性的getter,setter方法,如果有,则编译器会跳过,不会再生成,使用用户定义的方法。

深层理解

  • 用 _xx 访问时,在编译期程序就已经知道它的内存地址了,运行时是直接通过偏移量这种硬编码方式访问变量的内存地址;
    (1) 使用 _ 是获取不到父类的属性,因为它只是对局部变量的访问。
    (2) 另外,直接访问实例变量,将不会触发键值观测(KVO)的通知
  • 用 self.xx 访问时,是在运行时通过消息机制动态的访问变量的。
    (1) 从内存管理的视角看,根据属性修饰符的不同,setter方法并不仅仅是将传入的参数直接赋值给实例变量,而是经过了一些简单的操作(比如引用计数、原子性等)

实战经验

  • 尽管 _xx 的性能更好,如果不是必须,建议使用 self.xx,原因有(1)容易在 block 中造成循环引用 (2)直接访问实例变量,将不会触发键值观测(KVO)的通知。这样做是否会产生问题,还取决于具体的对象行为 (3)团队编码规范简单、统一。
  • 必须使用 _xx 的场景,比如重写 getter 或者 setter 时,内部不能再使用 self.xx 了

延伸思考

  • synthesize、dynamic 的用法?
  • 下面输出 _view1 的内容时有值吗?为什么?
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    _view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@", self.view1);
    });
}
  • getter、setter 一般是如何实现的?
  • 原子性是什么意思?
  • 引用计数的原理?

你可能感兴趣的:(iOS:self.xx vs self->_xx vs _xx)