第15条 用前缀避免命名空间冲突
最好遵循苹果的编程规范,使用 3个字的前缀。
对于全局的变量,常量以及C函数,也应该加上前缀。
第16条 提供“全能初始化方法“
这种编程模式就是定义一个参数最全的初始化方法,在其中初始化所有的成员变量,其余的初始化方法都调用这个初始化方法。目的是确保所有的成员变量都已经初始化,所有必要的过程都已经调用。
下边是书上的例子:
@implementation EOCRectangle
-(id)initWithWidth:(float)width andHeight:(float)height{
if(self = [super init]){
_width = width;
_height = height;
}
return self;
}
-(id)init{
return [self initWithWidth:5.0f andHeight:10.0f];
}
@end
如果用户使用默认的init函数初始化,会调用全能初始化函数得到一个宽5高10的长方形。这个例子其实不太好,对于矩形这个类来说,默认长宽为0可能是用户期望的。如果其他类,比如一个人,可能期望的默认名字是@“匿名”或者是@“”,而不是nil。(另外如果有未预料nil,在后续的操作中可能还会引起bug)。
总之,使用全能初始化函数能保证一个对象的所有成员变量默认都是自己设置的值。
在继承体系中,初始化函数有些复杂。比如有一个正方形类继承自EOCRectangle:
@implementation EOCSquare
-(id)initWithDimension:(float)dimension{
return [super initWithWidth:dimension andHeight:dimension];
}
@end
EOCSquare只需要一个参数就可以创建,因此提供了一个额外的初始化函数initWithDimension,在这个初始化函数中调用了基类ECORectangle的全能初始化函数。
但是用户在初始化的时候,仍然可以使用ECORectangle的initWithWidth:andHeight:方法,还有init方法。这样就可以创建出长和宽不等的正方形了。为了避免这种情况出现,又有了如下规则:
子类应该覆盖基类的全部全能初始化函数。
一个可能的实现是:
-(id)initWithWidth:(float)width andHeight:(float)height{
float dimension = MAX(width, height);
return [super initWithWidth:dimension andHeight:dimension];
}
如果在EOCSquare上调用init,此时self指向的是EOCSquare,因此会调用EOCSquare的initWithWidth:andHeight:方法。所以子类就不需要覆盖基类的init方法了。
上边的这套逻辑在Swift语言中可以通过编译器保证。
第17条 实现description方法
description和debugDescription是NSObject上的方法。自定义对象实现前者可以通过NSLog打印,实现后者可以实现在控制台po。
第18条 尽量使用不可变对象
这也是遵循了程序设计中的权限最小原则,使用不可变对象的好处显然是简单,你能确定这个值不会被修改。还有一个额外的好处就是在多线程环境下,不可变的对象可以简化编程难度。
有几个点:
1)如果对象的属性对外只读,但是内部可以修改,可以在扩展中使用readwrite改写。也可以在内部使用可变对象,对外提供一份不可变的copy。
2)readonly不能阻止外界使用KVC的方式改变
3)readonly更不能阻止外界通过运行时获取变量地址的方式改变