iOS 开发中的争议(一)

在 Objective-C 的语言的早期,类的私有成员变量是只能定义在 .h 的头文件里面的。像如下这样:

@interface ViewController : UIViewController {

@privateNSInteger _value;

}

之后,苹果改进了 Objective-C,允许在 .m 里面添加一个特殊的匿名 Category,即没有名字的 Category,来实现增加类的成员变量。像如下这样:

@interface ViewController ()

@property (nonatomic) NSInteger value;

@end

这样的好处是,这些变量在头文件中被彻底隐藏起来了,不用暴露给使用者。

接着,在 2013 年的 WWDC 中,苹果进一步改进了 Objective-C,允许在 .m 的@implementation中直接添加类的私有成员变量。像如下这样:

@implementation ViewController {

NSInteger _value;

}

于是,大家对于如何定义私有的成员变量上就产生的分歧。许多人喜欢用匿名的 Category 的方式来定义私有成员变量。但是,我个人更推荐在@implementation中直接添加类的私有成员变量。下面我做一些解释。

历史原因

首先早期的 iOS 程序员一定知道,在 2011 年 ARC 被推出之前,Objective-C 是需要手工地管理引用计数的。而对类的所有私有成员使用self.property的形式,就可以使编译器为我们自动生成管理引用计数的代码。在 2012 年前,这个 feature 还需要使用@synthesize关键字来启用的。于是,苹果通过在代码规范中推荐和强调使用self.property的编程习惯,来让大家避免在内存管理中遇到问题。而在 ARC 时代,这个编程习惯带来的优势不再存在了,因为编译器会自动为我们管理引用计数,我们只需要关心不要造成循环引用问题就行了。

省心省事

刚刚说到,在类中完全使用_property的方式来访问私有成员变量,是不会有内存管理上的问题的。但是使用self.property的方式来访问私有变量是不是也是一样不会有内存管理上的问题呢?确实也是,但是有一点需要注意:我们最好不要在 init 和 dealloc 中使用self.property的方式来访问成员变量,这一点是写在苹果的官方文档里的,我在以前的文章里也介绍过。(见:《不要在init和dealloc函数中使用accessor》

所以,如果你用self.property来访问私有成员变量。那么你需要注意,在 init 和 dealloc 中不使用这种方式。这其实对程序员来说是一个负担,你需要不停提醒自己有没有犯错。如果你使用完全的_property的方式来访问私有成员变量,就不用想这一类问题了。

关于隐藏

大家知道,self.property其实是调用了类的[self property]方法,所以这其实是有一层方法调用的隐藏,很多时候,我们需要延迟初使化一个类成员的时候,就会把这个成员的初使化方法写在这个[self property]方法的实现中。

那么问题来了,当你在阅读别人代码时,看到self.property的时候,你会想:这里会不会有一些隐藏的函数实现?于是你需要跳转到其方法实现中去查找。但是在实际开发中,大部分的 property 其实是使用编译器自动生成的 Getter 和 Setter 方法,于是你会找不到实现,这个时候,你才知道:“哦,原来这段代码并没有做自定义的成员初使化工作”。

这种默认的隐藏在代码中多了,会影响代码的阅读和维护。其实大部分的类成员变量都需要在类初使化方法中赋值,大部分的 UIViewController 的成员变量,都需要在viewDidLoad方法中赋值。那既然这样,不如直接在相应的方法中用一个名为setupProperty方法直接进行初使化。这样的好处是,代码的可读性更好了,self.property只有需要延迟初使化的情况下才被使用。

关于这个还有一个小故事,我之前 Review 过一个同事的 iOS 端代码,那个同事喜欢把 table view 的数据另外封装成一个类,而我觉得这些数据其实就是一个数组,没必要进行这一层封装,最终我们争论了比较久。我的观点是,一切隐藏都是对代码复杂性的增加,除非它带来了好处,例如达到了代码复用,提高了代码的可维护性等,否则,没有好处的封装只会给代码阅读理解带来成本。就我现在的经历中,大部分的 table view 的数据都可以放在一个数组中,没必要把这个数组封装起来,另外提供一套操作这个数组数据的方法。

简短的代码更易读

_property的写法比self.property更短,也更简单。我认为这样写出来的代码更方便阅读。

执行速度更快,IPA体积更小

我之前从来没想到过这两者之间的速度和应用体积会有很大差别。不过一个同行(来自国外著名的社交网络公司)告诉我,他们公司发现二者还是有不小的差距,如果你们的应用需要做一些深度优化,可以考虑一下把self.property换成_property。但我觉得,大部分应用都应该是不需要做这种深度优化的。

KVO 和 KVC

是的,如果用_property这种写法,就不能使用 KVO 和 KVC 了。但是我得反问一下,在一个类的内部,KVO 自己的私有成员变量算是一个好设计吗?我们讲类要”高内聚,低耦合”,KVO 是为了实现观察者模式,让对象之间相互解耦的。如果把 KVO 用在类的内部,KVO 自己的私有成员,我认为其实这不是一个很好的设计。

Computed Properties

在 Swift 中,引入了Computed Properties的概念,其实这在 Objective-C 中也有,只是没有专门给它名字。如果一个 property 我们提供了对应的setter和getter,并且没有直接使用其对应的 _property 变量,那么这个 property 就是所谓的 Computed Properties。

是的,在类的内部如果直接使用_property形式,也无法使用 Computed Properties 了,但我认为这影响不大。其实 Computed Properties 也就是一层对数据存取的封装,我们另外实现两个函数,分别对应数据的setter和getter功能,就可以达到同样的效果。

循环引用问题

微博上的@王_晓磊在评论中提到:直接用私有变量有个需要特别注意的地方,在 block 里直接写_property相当于self->_property,虽然没写 self,但是暗含了对 self 的retain,容易造成循环引用。要记得用 weakSelf/strongSelf 大法。

这一点确实是被很多人忽视的,所以我也一并写在这里,感谢他的补充。

写在最后

其实我上面提到的这些问题都是小问题,影响不大。但是代码风格的统一却是大问题。所以不管你们项目中使用的是self.property风格还是_property风格,问题都不大,但是如果你们同时使用这两种风格,那么就非常不好了。

希望我的这篇文章能让大家了解到在这方面的争论,也希望大家能够在这一点上,在公司内部达成统一。

转自这里。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,090评论 1 32
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,686评论 0 9
  • 境随心转
    打卡小能手阅读 85评论 0 0
  • 有没有那么一刻,悲从中来,所有的情绪不受控制,你沉默的站在街角,凌乱的回顾所有,你以为你一无所有,但其实你拥有整个...
    夜白安阅读 306评论 6 1