基本理解
- 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 一般是如何实现的?
- 原子性是什么意思?
- 引用计数的原理?
网友评论