Skip to content

Commit c060c9f

Browse files
author
ElonChan
committed
enhance article format
1 parent cbc4aa3 commit c060c9f

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

01《招聘一个靠谱的iOS》面试题参考答案/《招聘一个靠谱的iOS》面试题参考答案(上).md

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)