在我们一个项目中, 如果涉及多人开发,一般代码就会有多重风格,其中最明辨的,类的私有成员变量是如何定义的?
最常见的两种:
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) UITableView *tableView;
@interface ViewController() {
NSString *_name;
UITableView *_tableView;
}
历史原因探索:
在 2011 年 ARC 被推出之前,Objective-C 是需要手工地管理引用计数的。
而对类的所有私有成员使用self.property的形式,就可以使编译器为我们自动生成管理引用计数的代码。
在 2012 年前,这个时候还需要使用@synthesize关键字来启用的。
于是,苹果通过在代码规范中推荐和强调使用self.property的编程习惯,来让大家避免在内存管理中遇到问题。
而在 ARC 时代,这个编程习惯带来的优势不再存在了,因为编译器会自动为我们管理引用计数,我们只需要关心不要造成循环引用问题就行了。
而我的问题:平常我们在 ViewController 中使用属性后,到底是直接用实例变量还是?点属性使用?
@property (nonatomic, strong) UILabel *nameLabel;
// 实例变量的写法
_nameLabel = [[UILabel alloc] init];
// 直接属性的写法
self.nameLabel = [[UILabel alloc] init];
大致的区别:
- 由于不经过 Objective-C 的方法派发,直接访问实例变量的实数当然是比较快的。
- 直接访问实例变量的时候,不会调用其“设置方法”,这就绕过了为相关属性所定义的“内存管理语义啦”
- 如果直接访问实例变量,不会触发 KVO。
- 通过属性来访问有助于排查预支相关的错误,因为可以给“setter” 和 “getter”中新增断点,监控该属性的调用和访问的时间。
归纳基本原则
- 在对象内部时,使用实例变量来读取;
- 在写入数据是,则通过属性来写。
- 在 初始化方法以及 dealloc 中一般都是获取实例变量来读写数据。
- 懒加载的时候,设置肯定是实例变量,读取肯定是通过属性啦。
总的说来,在 ViewController 中无论使用哪一种风格,只要统一就好了,没有什么特别打的影响,但是我还是推荐在读取实例变量的时候采用直接访问的形式,设置实例变量的时候则通过属性来做。所以,我推荐在 ViewController 中使用self.property的风格,搭配懒加载的写法。
@property (nonatomic, strong) UILabel *nameLabel;
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.nameLabel];
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@100);
make.leading.equalTo(@30);
make.trailing.equalTo(@(-30));
make.height.equalTo(@40);
}];
}
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [[UILabel alloc] init];
}
return _nameLabel;
}