说明:面试题来源是微博@我就叫Sunny怎么了的这篇博文:《招聘一个靠谱的 iOS》,其中共55题,除第一题为纠错题外,其他54道均为简答题。
出题者简介: 孙源(sunnyxx),目前就职于百度,负责百度知道 iOS 客户端的开发工作,对技术喜欢刨根问底和总结最佳实践,热爱分享和开源,维护一个叫 forkingdog 的开源小组。
答案为微博@iOS程序犭袁整理,未经出题者校对,如有纰漏,请向微博@iOS程序犭袁指正。
1. 风格纠错题
修改完的代码:
修改方法有很多种,现给出一种做示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// .h文件 // http://weibo.com/luohanchenyilong/ // https://github.com/ChenYilong // 修改完的代码,这是第一种修改方法,后面会给出第二种修改方法 typedef NS_ENUM(NSInteger, CYLSex) { CYLSexMan, CYLSexWoman }; @interface CYLUser : NSObject<NSCopying> @property (nonatomic, copy, readonly) NSString *name; @property (nonatomic, assign, readonly) NSUInteger age; @property (nonatomic, assign, readonly) CYLSex sex; - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex; + (instancetype)userWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex; @end |
下面对具体修改的地方,分两部分做下介绍:硬伤部分和优化部分 。因为硬伤部分没什么技术含量,为了节省大家时间,放在后面讲,大神请直接看优化部分。
优化部分
- enum建议使用
NS_ENUM
和NS_OPTIONS
宏来定义枚举类型,参见官方的 Adopting Modern Objective-C 一文:12345//定义一个枚举typedef NS_ENUM(NSInteger, CYLSex) {CYLSexMan,CYLSexWoman}; - age属性的类型:应避免使用基本类型,建议使Foundation数据类型,对应关系如下:
1234int -> NSIntegerunsigned -> NSUIntegerfloat -> CGFloat动画时间 -> NSTimeInterval
同时考虑到age的特点,应使用NSUInteger,而非int。 这样做的是基于64-bit 适配考虑,详情可参考出题者的博文《64-bit Tips》。
- 如果工程项目非常庞大,需要拆分成不同的模块,可以在类、typedef宏命名的时候使用前缀。
- doLogIn方法不应写在该类中:虽然
LogIn
的命名不太清晰,但笔者猜测是login的意思,而登录操作属于业务逻辑,观察类名 UserModel ,以及属性的命名方式,该类应该是一个 Model 而不是一个“ MVVM 模式下的 ViewModel ”:
无论是MVC模式还是MVVM模式,业务逻辑都不应当写在Model里。
(如果抛开命名规范,假设该类真的是MVVM模式里的 ViewModel ,那么UserModel这个类可能对应的是用户注册页面,如果有特殊的业务需求,比如:login对应的应当是注册并登录的一个Button,出现login方法也可能是合理的。)
- doLogIn方法命名不规范:添加了多余的动词前缀。 请牢记:
如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用
do
,does
这种多余的关键字,动词本身的暗示就足够了。 -(id)initUserModelWithUserName: (NSString*)name withAge:(int)age;
方法中不要用with
来连接两个参数:withAge:
应当换为age:
,age:
已经足以清晰说明参数的作用,也不建议用andAge:
:通常情况下,即使有类似withA:withB:
的命名需求,也通常是使用withA:andB:
这种命名,用来表示方法执行了两个相对独立的操作(从设计上来说,这时候也可以拆分成两个独立的方法),它不应该用作阐明有多个参数,比如下面的:123456//错误,不要使用"and"来连接参数- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;//错误,不要使用"and"来阐明有多个参数- (instancetype)initWithName:(CGFloat)width andAge:(CGFloat)height;//正确,使用"and"来表示两个相对独立的操作- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;- 由于字符串值可能会改变,所以要把相关属性的“内存管理语义”声明为copy。(原因在下文有详细论述:用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?)
- “性别”(sex)属性的:该类中只给出了一种“初始化方法” (initializer)用于设置“姓名”(Name)和“年龄”(Age)的初始值,那如何对“性别”(Sex)初始化?
Objective-C 有 designated 和 secondary 初始化方法的观念。 designated 初始化方法是提供所有的参数,secondary 初始化方法是一个或多个,并且提供一个或者更多的默认参数来调用 designated 初始化方法的初始化方法。举例说明:
123456789说明:面试题来源是微博@我就叫Sunny怎么了的这篇博文:《招聘一个靠谱的 iOS》,其中共55题,除第一题为纠错题外,其他54道均为简答题。出题者简介: 孙源(sunnyxx),目前就职于百度,负责百度知道 iOS 客户端的开发工作,对技术喜欢刨根问底和总结最佳实践,热爱分享和开源,维护一个叫 forkingdog 的开源小组。
答案为微博@iOS程序犭袁整理,未经出题者校对,如有纰漏,请向微博@iOS程序犭袁指正。
1. 风格纠错题
修改完的代码:
修改方法有很多种,现给出一种做示例:
123456789101112131415161718192021// .h文件// http://weibo.com/luohanchenyilong/// https://github.com/ChenYilong// 修改完的代码,这是第一种修改方法,后面会给出第二种修改方法typedef NS_ENUM(NSInteger, CYLSex) {CYLSexMan,CYLSexWoman};@interface CYLUser : NSObject<NSCopying>@property (nonatomic, copy, readonly) NSString *name;@property (nonatomic, assign, readonly) NSUInteger age;@property (nonatomic, assign, readonly) CYLSex sex;- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex;+ (instancetype)userWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex;@end下面对具体修改的地方,分两部分做下介绍:硬伤部分和优化部分 。因为硬伤部分没什么技术含量,为了节省大家时间,放在后面讲,大神请直接看优化部分。
优化部分
- enum建议使用
NS_ENUM
和NS_OPTIONS
宏来定义枚举类型,参见官方的 Adopting Modern Objective-C 一文:12345//定义一个枚举typedef NS_ENUM(NSInteger, CYLSex) {CYLSexMan,CYLSexWoman}; - age属性的类型:应避免使用基本类型,建议使Foundation数据类型,对应关系如下:
1234int -> NSIntegerunsigned -> NSUIntegerfloat -> CGFloat动画时间 -> NSTimeInterval
同时考虑到age的特点,应使用NSUInteger,而非int。 这样做的是基于64-bit 适配考虑,详情可参考出题者的博文《64-bit Tips》。
- 如果工程项目非常庞大,需要拆分成不同的模块,可以在类、typedef宏命名的时候使用前缀。
- doLogIn方法不应写在该类中:虽然
LogIn
的命名不太清晰,但笔者猜测是login的意思,而登录操作属于业务逻辑,观察类名 UserModel ,以及属性的命名方式,该类应该是一个 Model 而不是一个“ MVVM 模式下的 ViewModel ”:
无论是MVC模式还是MVVM模式,业务逻辑都不应当写在Model里。
(如果抛开命名规范,假设该类真的是MVVM模式里的 ViewModel ,那么UserModel这个类可能对应的是用户注册页面,如果有特殊的业务需求,比如:login对应的应当是注册并登录的一个Button,出现login方法也可能是合理的。)
- doLogIn方法命名不规范:添加了多余的动词前缀。 请牢记:
如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用
do
,does
这种多余的关键字,动词本身的暗示就足够了。 -(id)initUserModelWithUserName: (NSString*)name withAge:(int)age;
方法中不要用with
来连接两个参数:withAge:
应当换为age:
,age:
已经足以清晰说明参数的作用,也不建议用andAge:
:通常情况下,即使有类似withA:withB:
的命名需求,也通常是使用withA:andB:
这种命名,用来表示方法执行了两个相对独立的操作(从设计上来说,这时候也可以拆分成两个独立的方法),它不应该用作阐明有多个参数,比如下面的:123456//错误,不要使用"and"来连接参数- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;//错误,不要使用"and"来阐明有多个参数- (instancetype)initWithName:(CGFloat)width andAge:(CGFloat)height;//正确,使用"and"来表示两个相对独立的操作- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;- 由于字符串值可能会改变,所以要把相关属性的“内存管理语义”声明为copy。(原因在下文有详细论述:用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?)
- “性别”(sex)属性的:该类中只给出了一种“初始化方法” (initializer)用于设置“姓名”(Name)和“年龄”(Age)的初始值,那如何对“性别”(Sex)初始化?
Objective-C 有 designated 和 secondary 初始化方法的观念。 designated 初始化方法是提供所有的参数,secondary 初始化方法是一个或多个,并且提供一个或者更多的默认参数来调用 designated 初始化方法的初始化方法。举例说明:
- enum建议使用