读《招聘一个靠谱的 iOS》-- 代码风格

来源:互联网 发布:淘宝买家数据购买 编辑:程序博客网 时间:2024/04/28 08:34

题目:
尝试修改以下代码中的风格错误:
这里写图片描述

———————————————————我是分割线——————————————————–

博主在平时code时一直很注重自己的代码风格,固在修改此题可以说是信心十足,但修改下来也就发现9处错误,还只是一些浅显的“硬伤”,没有什么技术含量,而结合网上的一些错误修改却发现十多条的“可优化部分”!
真是平时没有严格要求住自己,才会让自己把一些错误的事情当做正确的事情来执行!

———————————————————我是分割线——————————————————–
先附上网上的一种优秀的修改方法 (稍加修改版):

typedef NS_ENUM(NSInteger, DBSex) {    DBSexMan,    DBSexWoman};@interface DBUser : NSObject<NSCopying>@property (nonatomic, copy  , readonly) NSString *name;@property (nonatomic, assign, readonly) NSUInteger age;@property (nonatomic, assign, readonly) DBSex sex;- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(DBSex)sex;- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age;@end

下面对具体修改的地方,分两部分做下介绍:硬伤部分和优化部分
。因为硬伤部分没什么技术含量,为了节省大家时间,放在后面讲,大神请直接看优化部分。

可优化部分(代码由上往下看):
1、enum
enum官方给出的推荐方法中已经摒弃简单的typedef enum这种写法了,而是用NS_ENUMNS_OPTIONS 宏来定义枚举类型,参见官方的 Adopting Modern Objective-C 一文:
举例:

//定义一个枚举typedef NS_ENUM(NSInteger, DBSex) {    DBSexMan,    DBSexWoman};

2、一般类名需要在加上前缀,用以分割项目中的所属模块或者与第三方类区分

3、熟悉定义的时候优于原子属性(nonatomic)在绝大多数情况下是需要的,所以统一写在第一位,观察下面有该类的初始化方法,固猜测此此类中属性是不允许随意被外界修改的(需要修改需要有特定的方法),所以在属性中需要加上readonly属性。

得出修改结果:

@property (nonatomic, copy  , readonly) NSString *name;@property (nonatomic, assign, readonly) NSUInteger age;@property (nonatomic, assign, readonly) DBSex sex;

注:后面的文章会说到为什么要把strong改成copy,大概可以理解为指针本身的地址指针指向的地址的区别,说白了就是浅复制和深复制的区别。

4、NSIntegerNSUIntegerNSTimeIntervalCGFloatintfloatunsigned

int -> NSIntegerunsigned -> NSUIntegerfloat -> CGFloat动画时间 -> NSTimeInterval

从命名所表达的意思来看,属性age应该代表的是岁数,而岁数为非负整数,所以使用NSUInteger优于int。

这样做的是基于64-bit 适配考虑,详情可参考出题者的博文《64-bit Tips》

5、方法命名不规范

-(id)initUserModelWithUserName: (NSString*)name withAge:(int)age;

观察方法名,不难理解到此方法适用于用参数来初始化一个实力DBUser方法,所以:
1) 返回类型id改为instancetype会更加明了;
2) 名称用init足以表达意思initUserModel会略显臃肿;
3) 参数需要遵循原则:**with连接第一个独立个参数,相对独立参数用and连接,并列参数不要任何任何动词连接。**(此处仅代表博主个人意见,如有不同,请指出!)

//错误,不要使用"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;

4) 初始化时漏掉参数sex,在不太改动原来方法的情况下,应该拆分为两个独立的方法。

最后得出结果:

- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(DBSex)sex;- (instancetype)initWithName:(NSString *)name age:(NSUInteger)age;

doLogIn方法命名不规范:添加了多余的动词前缀。 请牢记:

如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用do,does这种多余的关键字,动词本身的暗示就足够了。

6、MVC而非MVVM
由于博主代码风格一值都是使用MVVM,所以对此不做过多评价,所以贴出大神原话:

doLogIn方法不应写在该类中:虽然LogIn的命名不太清晰,但笔者猜测是login的意思,而登录操作属于业务逻辑,观察类名UserModel,以及属性的命名方式,应该使用的是MVC模式,并非MVVM,在MVC中业务逻辑不应当写在Model中。(如果是MVVM,抛开命名规范,UserModel这个类可能对应的是用户注册页面,如果有特殊的业务需求,比如:login对应的应当是注册并登录的一个Button,出现login方法也可能是合理的。)

注:即使是在MVVM中,login这种方法也不应该出现再次出,此类偏向于数据模型,并不属于业务逻辑范畴。

硬伤部分1.在-和(void)之间应该有一个空格2.enum中驼峰命名法和下划线命名法混用错误:枚举类型的命名规则和函数的命名规则相同:命名时使用驼峰命名法,勿使用下划线命名法。3.enum左括号前加一个空格,或者将左括号换到下一行4.enum右括号后加一个空格5.UserModel :NSObject 应为UserModel : NSObject,也就是:右侧少了一个空格。6.@interface与@property属性声明中间应当间隔一行。7.两个方法定义之间不需要换行,有时为了区分方法的功能也可间隔一行,但示例代码中间隔了两行。8.-(id)initUserModelWithUserName: (NSString*)name withAge:(int)age;方法中方法名与参数之间多了空格。而且- 与(id)之间少了空格。9.-(id)initUserModelWithUserName: (NSString*)name withAge:(int)age;方法中方法名与参数之间多了空格:(NSString*)name前多了空格。10.-(id)initUserModelWithUserName: (NSString*)name withAge:(int)age;方法中(NSString*)name,应为(NSString *)name,少了空格。11.doLogIn方法命名不清晰:笔者猜测是login的意思,应该是粗心手误造成的。12.第二个@property中assign和nonatomic调换位置。
0 0
原创粉丝点击