打算分享一些有争议的话题,发表一下自己的看法。这是本系列的第一篇文章。我想讨论的是:类的成员变量应该怎么定义?在早期的Objective-C语言中,一个类的私有成员变量只能定义在.h头文件中。像这样:@interfaceViewController:UIViewController{@privateNSInteger_value;}之后Apple改进了Objective-C,允许在.m中加入一个特殊的匿名Category,即没有名字的Category,增加类的成员变量.像这样:@interfaceViewController()@property(nonatomic)NSIntegervalue;@end这样做的好处是这些变量完全隐藏在头文件中,不需要暴露给用户。然后,在2013年的WWDC上,Apple进一步改进了Objective-C,允许在.m的@implementation中直接添加类的private成员变量。像这样:@implementationViewController{NSInteger_value;}所以,大家对私有成员变量的定义方式意见不一。许多人更喜欢将私有成员变量定义为匿名Category。但是,我个人建议直接在@implementation中添加类的私有成员变量。让我作一些解释。历史原因首先,早期的iOS程序员肯定知道,在2011年ARC推出之前,Objective-C需要手动管理引用计数。对类的所有私有成员使用self.property的形式可以让编译器自动生成代码来为我们管理引用计数。在2012年之前,此功能是使用@synthesize关键字启用的。所以Apple在代码规范中推荐并强调使用self.property的编程习惯,避免大家在内存管理上遇到问题。在ARC时代,这种编程习惯带来的优势不复存在,因为编译器会自动帮我们管理引用计数,我们只需要关心不会引起循环引用问题即可。刚才说了,在类中使用_property访问私有成员变量不会造成内存管理问题。但是使用self.property来访问私有变量,不存在内存管理问题不也是一样的吗?的确如此,但是有一点需要注意:在init和dealloc中一定不能使用self.property来访问成员变量,这个在苹果官方文档中是有写的,我在上一篇文章Pass中也介绍过。(参见:《不要在init和dealloc函数中使用accessor》)所以,如果使用self.property来访问私有成员变量。然后需要注意,不要在init和dealloc中使用这个方法。这对程序员来说其实是一种负担,你需要不断提醒自己有没有犯错。如果使用完整的_property方式访问私有成员变量,就不用考虑这种问题了。隐藏我们都知道,self.property其实是调用了类的[selfproperty]方法,所以这其实是一层方法调用隐藏。很多时候,当我们需要延迟类成员的初始化时,我们会把这个成员的初始化方法写在这个[selfproperty]方法的实现中。那么问题来了,当你在看别人代码的时候看到self.property,你会想:这里是不是有什么隐藏的功能实现?所以需要跳转到它的方法实现中去寻找。但是在实际开发中,大部分的属性其实都是使用编译器自动生成的Getter和Setter方法,所以你会找不到实现。这时候你就知道了:“哦,这个代码不是定制的,小组成员最初制作作品”。这个默认在代码中隐藏的太多了,会影响代码的阅读和维护。其实大部分的类成员变量都需要在类初始化方法中赋值,UIViewController的大部分成员变量都需要在viewDidLoad方法中赋值。在这种情况下,最好使用一个名为setupProperty的方法直接在相应的方法中进行初始化。这样做的好处是代码可读性更强,self.property只有在需要延迟初始化的时候才使用。关于这件事还有一个小故事。之前看过一个同事的iOS代码。那个同事喜欢把tableview的数据封装到另一个类里,我觉得这些数据其实就是一个数组,就不需要这层封装了,最后我们争论了很久。我的观点是,所有的隐藏都是代码复杂度的增加,除非它带来好处,比如实现代码重用,提高代码可维护性等,否则,没有好处的封装只会让代码的可读性理解是有代价的.根据我目前的经验,大多数表视图数据都可以放在一个数组中。不需要封装这个数组,提供一套操作数组数据的方法。短代码更易于阅读_property比self.property更短更简单。我认为这样写的代码更容易阅读。更快的执行,更小的IPA大小我以前从未想过两者之间在速度和应用程序大小上会有很大的差异。但是,一位同事(来自国外某知名社交网络公司)告诉我,他们公司发现两者之间还有很大的差距。如果你的应用需要做一些深度优化,可以考虑将self.property替换为_property。但我认为大多数应用程序应该不需要做这种深度优化。KVO和KVC是的,如果使用_property,就不能使用KVO和KVC。但是我要问,在一个类里面,KVO自己的私有成员变量是不是一个好的设计?我们说类应该是“高内聚,低耦合”。KVO是实现观察者模式,对象之间解耦。如果在类内部使用KVO,KVO自己的私有成员,我觉得这其实不是一个很好的设计。ComputedProperties介绍了Swift中ComputedProperties的概念。其实在Objective-C中也有,只是没有专门的名字而已。如果我们为一个属性提供了对应的setter和getter,而不直接使用它对应的_property变量,那么这个属性就称为ComputedProperties。是的,如果直接在类内部使用_property形式就不能使用ComputedProperties,但我认为这不会有太大影响。ComputedProperties其实就是对数据访问的一层封装。我们实现了另外两个函数,分别对应数据的setter和getter函数,达到同样的效果。写在***其实我上面提到的问题都是小问题,影响不大。但是代码风格的统一是个大问题。所以无论你在项目中使用self.property样式还是_property样式,问题都不大,但是如果同时使用这两种样式,那就很糟糕了。我希望我的这篇文章能够让大家了解这方面的争论,也希望大家能够在公司内部就这一点达成共识。
