@@ -89,22 +89,24 @@ typedef NS_ENUM(NSInteger, CYLSex) {
8989
9090
9191
92- 下面对具体修改的地方,分两部分做下介绍:*** 硬伤部分*** 和 *** 优化部分* **
93- 。因为*** 硬伤部分*** 没什么技术含量,为了节省大家时间,放在后面讲,大神请直接看*** 优化部分* ** 。
92+ 下面对具体修改的地方,分两部分做下介绍:** 硬伤部分** 和 ** 优化部分**
93+ 。因为** 硬伤部分** 没什么技术含量,为了节省大家时间,放在后面讲,大神请直接看** 优化部分** 。
9494
9595
96- #### *** 优化部分* **
96+ #### ** 优化部分**
9797
98- 4 . enum 建议使用 ` NS_ENUM ` 和 ` NS_OPTIONS ` 宏来定义枚举类型,参见官方的 [ Adopting Modern Objective-C] ( https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html ) 一文:
98+ 1 . enum 建议使用 ` NS_ENUM ` 和 ` NS_OPTIONS ` 宏来定义枚举类型,参见官方的 [ Adopting Modern Objective-C] ( https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html ) 一文:
9999
100- ``` objective-c
100+
101+ ``` objective-c
101102// 定义一个枚举
102103 typedef NS_ENUM (NSInteger, CYLSex) {
103104 CYLSexMan,
104105 CYLSexWoman
105106 };
106- ```
107+ ```
107108 (仅仅让性别包含男和女可能并不严谨,最严谨的做法可以参考 [这里](https://github.com/ChenYilong/iOSInterviewQuestions/issues/9) 。)
109+
108110 2. age 属性的类型:应避免使用基本类型,建议使用 Foundation 数据类型,对应关系如下:
109111
110112 ```Objective-C
@@ -117,23 +119,23 @@ typedef NS_ENUM(NSInteger, CYLSex) {
117119这样做的是基于64-bit 适配考虑,详情可参考出题者的博文[ 《64-bit Tips》] ( http://blog.sunnyxx.com/2014/12/20/64-bit-tips/ ) 。
118120
119121
120- 5 . 如果工程项目非常庞大,需要拆分成不同的模块,可以在类、typedef宏命名的时候使用前缀。
121- 6 . doLogIn方法不应写在该类中: <p ><del >虽然` LogIn ` 的命名不太清晰,但笔者猜测是login的意思, (勘误:Login是名词,LogIn 是动词,都表示登陆的意思。见: [ *** Log in vs. login*** ] ( http://grammarist.com/spelling/log-in-login/ ) )</del ></p >登录操作属于业务逻辑,观察类名 UserModel ,以及属性的命名方式,该类应该是一个 Model 而不是一个“ MVVM 模式下的 ViewModel ”:
122+ 3 . 如果工程项目非常庞大,需要拆分成不同的模块,可以在类、typedef宏命名的时候使用前缀。
123+ 4 . doLogIn方法不应写在该类中: <p ><del >虽然` LogIn ` 的命名不太清晰,但笔者猜测是login的意思, (勘误:Login是名词,LogIn 是动词,都表示登陆的意思。见: [ *** Log in vs. login*** ] ( http://grammarist.com/spelling/log-in-login/ ) )</del ></p >登录操作属于业务逻辑,观察类名 UserModel ,以及属性的命名方式,该类应该是一个 Model 而不是一个“ MVVM 模式下的 ViewModel ”:
122124
123125
124126 > 无论是 MVC 模式还是 MVVM 模式,业务逻辑都不应当写在 Model 里:MVC 应在 C,MVVM 应在 VM。
125127
126128
127129 (如果抛开命名规范,假设该类真的是 MVVM 模式里的 ViewModel ,那么 UserModel 这个类可能对应的是用户注册页面,如果有特殊的业务需求,比如: ` -logIn ` 对应的应当是注册并登录的一个 Button ,出现 ` -logIn ` 方法也可能是合理的。)
128130
129- 7 . doLogIn 方法命名不规范:添加了多余的动词前缀。
131+ 5 . doLogIn 方法命名不规范:添加了多余的动词前缀。
130132请牢记:
131133
132134 > 如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用 ` do ` ,` does ` 这种多余的关键字,动词本身的暗示就足够了。
133135
134136 应为 ` -logIn ` (注意: ` Login ` 是名词, ` LogIn ` 是动词,都表示登陆。 见[ *** Log in vs. login*** ] ( http://grammarist.com/spelling/log-in-login/ ) )
135137
136- 11 . ` -(id)initUserModelWithUserName: (NSString*)name withAge:(int)age; ` 方法中不要用 ` with ` 来连接两个参数: ` withAge: ` 应当换为` age: ` ,` age: ` 已经足以清晰说明参数的作用,也不建议用 ` andAge: ` :通常情况下,即使有类似 ` withA:withB: ` 的命名需求,也通常是使用` withA:andB: ` 这种命名,用来表示方法执行了两个相对独立的操作(* 从设计上来说,这时候也可以拆分成两个独立的方法* ),它不应该用作阐明有多个参数,比如下面的:
138+ 6 . ` -(id)initUserModelWithUserName: (NSString*)name withAge:(int)age; ` 方法中不要用 ` with ` 来连接两个参数: ` withAge: ` 应当换为` age: ` ,` age: ` 已经足以清晰说明参数的作用,也不建议用 ` andAge: ` :通常情况下,即使有类似 ` withA:withB: ` 的命名需求,也通常是使用` withA:andB: ` 这种命名,用来表示方法执行了两个相对独立的操作(* 从设计上来说,这时候也可以拆分成两个独立的方法* ),它不应该用作阐明有多个参数,比如下面的:
137139
138140 ``` objective-c
139141// 错误,不要使用"and"来连接参数
@@ -144,8 +146,8 @@ typedef NS_ENUM(NSInteger, CYLSex) {
144146- (BOOL )openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL )flag;
145147```
146148
147- 12 . 由于字符串值可能会改变,所以要把相关属性的“内存管理语义”声明为 copy 。(原因在下文有详细论述:*** 用@property 声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?*** )
148- 2 . “性别”(sex)属性的:该类中只给出了一种“初始化方法” (initializer)用于设置“姓名”(Name)和“年龄”(Age)的初始值,那如何对“性别”(Sex)初始化?
149+ 7 . 由于字符串值可能会改变,所以要把相关属性的“内存管理语义”声明为 copy 。(原因在下文有详细论述:*** 用@property 声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?*** )
150+ 8 . “性别”(sex)属性的:该类中只给出了一种“初始化方法” (initializer)用于设置“姓名”(Name)和“年龄”(Age)的初始值,那如何对“性别”(Sex)初始化?
149151
150152 Objective-C 有 designated 和 secondary 初始化方法的观念。 designated 初始化方法是提供所有的参数,secondary 初始化方法是一个或多个,并且提供一个或者更多的默认参数来调用 designated 初始化方法的初始化方法。举例说明:
151153
@@ -222,8 +224,8 @@ typedef NS_ENUM(NSInteger, CYLSex) {
222224 ` .h ` 中暴露 designated 初始化方法,是为了方便子类化 (想了解更多,请戳--》 [ *** 《禅与 Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译)》*** ] ( http://is.gd/OQ49zk ) 。)
223225
224226
225- 2 . 按照接口设计的惯例,如果设计了“初始化方法” (initializer),也应当搭配一个快捷构造方法。而快捷构造方法的返回值,建议为 instancetype,为保持一致性,init 方法和快捷构造方法的返回类型最好都用 instancetype。
226- 2 . 如果基于第一种修改方法:既然该类中已经有一个“初始化方法” (initializer),用于设置“姓名”(Name)、“年龄”(Age)和“性别”(Sex)的初始值:
227+ - 按照接口设计的惯例,如果设计了“初始化方法” (initializer),也应当搭配一个快捷构造方法。而快捷构造方法的返回值,建议为 instancetype,为保持一致性,init 方法和快捷构造方法的返回类型最好都用 instancetype。
228+ - 如果基于第一种修改方法:既然该类中已经有一个“初始化方法” (initializer),用于设置“姓名”(Name)、“年龄”(Age)和“性别”(Sex)的初始值:
227229那么在设计对应 ` @property ` 时就应该尽量使用不可变的对象:其三个属性都应该设为“只读”。用初始化方法设置好属性值之后,就不能再改变了。在本例中,仍需声明属性的“内存管理语义”。于是可以把属性的定义改成这样
228230
229231
@@ -234,10 +236,11 @@ typedef NS_ENUM(NSInteger, CYLSex) {
234236 ```
235237
236238 由于是只读属性,所以编译器不会为其创建对应的“设置方法”,即便如此,我们还是要写上这些属性的语义,以此表明初始化方法在设置这些属性值时所用的方式。要是不写明语义的话,该类的调用者就不知道初始化方法里会拷贝这些属性,他们有可能会在调用初始化方法之前自行拷贝属性值。这种操作多余而且低效。
237- 2 . ` initUserModelWithUserName ` 如果改为 ` initWithName ` 会更加简洁,而且足够清晰。
238- 2 . ` UserModel ` 如果改为 ` User ` 会更加简洁,而且足够清晰。
239- 2 . ` UserSex ` 如果改为` Sex ` 会更加简洁,而且足够清晰。
240- 2 . 第二个 ` @property ` 中 assign 和 nonatomic 调换位置。
239+
240+ 9 . ` initUserModelWithUserName ` 如果改为 ` initWithName ` 会更加简洁,而且足够清晰。
241+ 10 . ` UserModel ` 如果改为 ` User ` 会更加简洁,而且足够清晰。
242+ 11 . ` UserSex ` 如果改为` Sex ` 会更加简洁,而且足够清晰。
243+ 12 . 第二个 ` @property ` 中 assign 和 nonatomic 调换位置。
241244 推荐按照下面的格式来定义属性
242245
243246 ``` Objective-C
@@ -289,16 +292,16 @@ NSlnteger 等)的简单赋值操作。
289292 block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。你也许会感觉我这种做法有些怪异,不需要写依然写。如果你这样想,其实是你“日用而不知”,你平时开发中是经常在用我说的这种做法的,比如下面的属性不写copy也行,但是你会选择写还是不写呢?
290293
291294 ``` Objective-C
292- @property (nonatomic, copy) NSString *userId;
295+ @property (nonatomic, copy) NSString *userId;
293296
294- - (instancetype )initWithUserId:(NSString *)userId {
297+ - (instancetype )initWithUserId:(NSString *)userId {
295298 self = [super init];
296299 if (!self) {
297300 return nil;
298301 }
299302 _userId = [userId copy];
300303 return self;
301- }
304+ }
302305
303306 ```
304307
0 commit comments