第1条 了解objective-c的起源
objective-c是消息结构(message structure),而C++、Java是函数调用(function calling),二者区别:
NSString *someString = @"hello world!";
NSString *anotherSomeString = someString;
someString实际上就是一个指向字符串的指针。
第2条 在类的头文件中尽量少引入其他头文件
使用@class
前向声明,降低耦合,也能缩短编译时间。
遵循某个协议,最好在.m
文件的extension
里写,同样是可以节约编译时间,也可减少彼此依赖程度。
第3条 多用字面量,少用与之等价的方法
若如下写代码会报错:
NSObject *obj1 = @"1";
NSObject *obj2 = nil;
NSArray *arr1 = [NSArray arrayWithObjects:obj1, obj2, nil];
NSArray *arr2 = @[obj1, obj2];
arr2时会报错,因为字面量写法实际上是一种“语法糖”(syntactic sugar)相当于先建了个数组,再往数组里insert对象。arr1虽然未报错,但是实际上只有obj1插入成功了,所以字面量更加安全,如果有错开发者能很好地定位到。
*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[1]
字典也如此,一旦有nil就会抛出异常。
字面量创建出来的都是不可变的,要想实现可变,需要 mutableCopy 一份。
NSMutableArray *muArr = [@[@"obj1", @"obj2"] mutableCopy];
第4条 多用类型常量,少用#define预处理命令
#define ANIMATION_DURATION 0.3
static const NSTimeInterval ANIMATION_DURATION 0.3;
- 用
#define
的缺点:
- 缺少类型信息
- 如果写在
.h
文件中,则会将所有引用改头文件的地方的ANIMATION_DURATION
都替换为0.3
。
- 命名方法:
若在.m
里写的,则前面加个k
;若在.h
里写的,则前面加个类名,如在LYClass.h
写的,就写成LYClassANIMATION_DURATION
,可以跟防止别的类重复。
事实上,最好也别在 .h 文件里定义,即在.h里声明,在.m里定义,注意 const 在语句中的位置。extern 的作用相当于告诉编译器,全局符号表中有个 LYClassStringConstant 的常量,当编译生成二级制包后,所有调用该常量的地方,链接器都能解析。
// .h 文件
extern NSString *const LYClassStringConstant;
// .m 文件
NSString *const LYClassStringConstant = @"Value";
第5条 用枚举表示状态、选项、状态码
enum SFConflictActionType {
SFUnknowConflictAction,
SFReplaceConflictAction,
SFKeepbothConflictAction,
};
实现枚举所用的数据类型取决于编译器,不过其二进制位(bit)的个数必须能完全表示下枚举编号才行。在上例中,由于最大编号为2,所以使用1个字符的char类型即可。
C++11 标准修订了枚举的某些特性,其中一项改动是:可以指明用何种数据类型来保存枚举类型的变量。这样的好处是,可以前向声明枚举类型变量了。若不指定底层数据类型,则无法向前声明枚举类型,因为编译器不清楚底层数据类型的大小,所以在用到此枚举类型时,也就不知道究竟分配多少空间。
enum SFConflictActionType : NSInteger { /*...*/ };
比较好的一种写法:
typedef NS_ENUM (NSInteger, SFConflictActionType) {
SFUnknowConflictAction,
SFReplaceConflictAction,
SFKeepbothConflictAction,
};
还有一种情况应该用枚举,就是定义选项的时候。若这些选项可以彼此组合,则更应如此。只要枚举定义的对,各选项间就可以通过“按位活操作符”来组合。如,iOS UI框架中有如下枚举:
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0, // 即 1
UIViewAutoresizingFlexibleWidth = 1 << 1, // 即 2
UIViewAutoresizingFlexibleRightMargin = 1 << 2, // 即 4
UIViewAutoresizingFlexibleTopMargin = 1 << 3, // 即 8
UIViewAutoresizingFlexibleHeight = 1 << 4, // 即 16
UIViewAutoresizingFlexibleBottomMargin = 1 << 5 // 即 32
};
要点:
通过按位运算定义枚举的好处是,可以用单个判断来判断多选,否则要判断多个情况。