第一题
l题目:风格纠错题
能够达到10处以上修改就属于达标。
l分析:
Enum,也就是枚举,是名称和值的组合,从C语言开始就有了,C++、Java、Objective-C、Swift这些语言,当然都有对应的枚举类型,功能可能有多有少,但是最核心的还是一个—规范的定义代码中的状态、选项等“常量”。
状态与选项的区别(states and options)
在用enum之前,我个人觉得,区分一下状态和选项的概念还是很必要的。
状态,同时只能有一种,如“OK”,“Error”,不可能同时是OK和Error。
选项,同时可以有一种或一种以上,如App可以同时支持横屏和竖屏,横屏竖屏在这个时候就是“屏幕方向”的两种不同的选项。
接下来,我们看看如何用枚举定义状态和选项。
enum与状态(states)
不好的做法
经常看到这样的写法:
#define STATE_OK 0
#define STATE_ERROR 1
#define STATE_UNKNOW 2
//直接用int型变量接收
int STATE = STATE_UNKNOW;
这样做有如下“不恰当”:
•宏定义没有类型约束,只是单纯的替换。
•无法限制状态的所有情况,如,认为的将STATE赋值成3,程序可能就会出错,找不到匹配的状态,因为编译器不会对“STATE = 3;”提出警告。
正确的做法
typedef enum _State {
StateOK= 0,
StateError,//(编译器会自动赋值,默认从零开始,默认是int)
StateUnknow
} State;
//指明枚举类型
State state = StateOK;
用的时候就如下:
- (void)dealWithState:( State)state {
switch (state) {
case StateOK:
//...
break;
case StateError:
//...
break;
case StateUnknow:
//...
break;
}
}
enum与选项(options)
选项,就是说一个“选项变量”的类型要能够同时表示一个或多个组合的选择,如下例子:
//方向,可同时支持一个或多个方向
typedef enum _Direction {
DirectionNone = 0,
DirectionTop = 1 << 0,//1左移0位,0001
DirectionLeft = 1 << 1,//左移1位,0010
DirectionRight = 1 << 2,//左移2位,0100
DirectionBottom = 1 << 3//左移3位,1000
} Direction;
看,这里的选项是用位运算的方式定义的,这样的好处就是,我们的选项变量可以如下表示:
//用“或”运算同时赋值多个选项
Direction direction = DirectionTop | DirectionLeft | DirectionBottom;
//用“与”运算取出对应位
if (direction & DirectionTop) {//1011 & 0001
NSLog(@"top");
}
if (direction & DirectionLeft) {
NSLog(@"left");
}
if (direction & DirectionRight) {
NSLog(@"right");
}
if (direction & DirectionBottom) {
NSLog(@"bottom");
}
direction变量的实际内存如下:
这样,用位运算,就可以同时支持多个值。
enum在Objective-C中的“升级版”
一般来说,我们不能指定枚举变量的实际类型是什么,就是说,我们不知道枚举最后是int型,还是其他的什么类型。但是从C++ 11开始,我们可以为枚举指定其实际的存储类型,如下语法:
enum State : NSInteger {/*...*/};
但是,我们在定义枚举的时候如何保证兼容性呢?Foundation框架已经为我们提供了更加“统一、便捷”的枚举定义方法,我们重新定义上面的例子:
//NS_ENUM,定义状态等普通枚举
typedef NS_ENUM(NSUInteger, State) {
StateOK = 0,
StateError,
StateUnknow
};
//NS_OPTIONS,定义选项
typedef NS_OPTIONS(NSUInteger, Direction) {
DirectionNone = 0,
DirectionTop = 1 << 0,
DirectionLeft = 1 << 1,
DirectionRight = 1 << 2,
DirectionBottom = 1 << 3
};
所以,在开发Mac、iOS程序中,最好所有的枚举都用“NS_ENUM”和“NS_OPTIONS”定义,保证统一。
Id和instancetype,根据Cocoa的命名规则,满足下述规则的方法:
1,类方法中,以alloc或new开头
2,实例方法中,以autorelease,init,retain或self开头
会返回一个方法所在类类型的对象,这些方法就被称为是关联返回类型的方法。换句话说,这些方法的返回结果以方法所在的类为类型,而除此之外的方法,会返回id类型。Instancetype就是使那些非关联返回类型的方法返回所在类的类型
l答案
1,typedef enum{
UserSex_Man,
UserSex_Woman
}UserSex;修改为
typedef NS_ENUM(NSInteger,UserSex){
UserSex_Man,
UserSex_Woman
};
2,数据类型:应避免使用基本类型,建议使用Foundation数据类型。如:int->NSInteger,unsigned->NSUInteger,float->CGFloat。
3,doLogIn方法不应该写在该类中,登陆操作属于业务逻辑,不应该写在Model中。
4,doLogIn方法命名不规范:添加了多余的动词前缀。如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用do,does这种多余的关键字,动词本身的暗示就够了。
5,-(id)initUserModelWithUserName:
(NSString*)name withAge:(int)age;方法中withAge:应当换为age:,age已经足以。
6,@property声明的NSString(或NSArray,NSDictionary)最好使用copy关键字
7,该类中只给出了一种“初始化方法” (initializer)用于设置“姓名”(Name)和“年龄”(Age)的初始值,那如何对“性别”(Sex)初始化?
8,初始化的返回类型中,id最好改为instancetype,理由见分析。
其他硬伤部分:
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调换位置。
13)initUserModelWithUserName如果改为initWithName会更加简洁,而且足够清晰。
14)UserModel如果改为User会更加简洁,而且足够清晰。
15)UserSex如果改为Sex会更加简洁,而且足够清晰。