选择与你公司、应用程序或者皆有关联的名称作为类的前缀,并在代码中均使用这一前缀。
若自己所开发的 App 使用到第三方库,则应为其的名称加上前缀。
1. 提供初始化方法
如果创建类实例的方式不止一种,那么这个类就会有多个初始化方法。不过要在其中选中一个作为全能初始化方法,并做到其他初始化方法都调用它。
比如说,编写一个表示矩形的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #import <Foundation/Foundation.h> @interface EOCRectangle : NSObject @property (nonatomic, assign, readonly) float width; @property (nonatomic, assign, readonly) float height; @end -(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]; } - (id)init { @throw [NSException exceptionWithName: NSInternalInconsistencyException reason: @"请使用便利初始化方法" userInfo: nil]; }
|
假设我们现在要创建一个 EOCSquare 类,令其成为 EOCRectangle 的子类,下面是子类的初始化方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #import "EOCRectangle.h" @interface EOCSquare : EOCRectangle - (id)initWithDimension:(float)dimension; @end @implementation EOCSquare - (id)initWithDimension:(float)dimension { return [super initWithWidth: dimension andHeight: dimension]; } - (id)initWithWidth:(float)width andHeight:(float)height { float dimension = MAX(width, height); return [self initWithDimension: dimension]; } - (id)init { return [self initWithDimension: 5.0]; } @end
|
这里有一个特别的情况,某个类可能存在两个全能初始化方法。比如我们让 EOCRectangle 遵守 NSCoding 协议,从而实现此类的序列化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @interface EOCRectangle : NSObject <NSCoding> @property (nonatomic, assign, readonly) CGFloat width; @property (nonatomic, assign, readonly) CGFloat height; - (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height; @end @implementation EOCRectangle - (instancetype)initWithCoder:(NSCoder *)aDecoder { / if (self = [super init]) { _width = [aDecoder decodeFloatForKey:@"width"]; _height = [aDecoder decodeFloatForKey:@"height"]; } return self; } @interface EOCSquare : EOCRectangle <NSCoding> @end @implementation EOCSquare - (instancetype)initWithCoder:(NSCoder *)aDecoder { if (self = [super initWithCoder:aDecoder]) { } return self; } @end
|
因此可以看到,在自定义类时需要提供一个全能初始化方法,并尽量在文档中指出,其他初始化方法均应调用此方法。
如果全能初始化方法与超类不同,应该重写超类中对应的方法。
如果超类的初始化方法不适合与子类,那么可以选择重写超类的这个方法,并在其中抛出异常。
2. 实现 description 方法
调试程序时,我们往往希望在控制台打印出更丰富的信息。而在某个类构建需要打印到日志的字符串时,会收到 description 消息,我们通过重写此方法就可以自定义描述信息了。下面这个例子展示了一种不错的输出格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p, %@>", [self class], self, @{@"width":@(_width), @"height": @(_height), }]; } 22:52:11.691 Ads[8785:2103515] <EOCRectangle: 0x600000036600, { height = 10; width = 5; }>
|
3. 尽量使用不可变对象
这点和 swift 中的应用一样,只有在必要的时候才将对象定义为可变。而在 OC 中声明属性时默认是 readwrite 的。