第16條:提供“全能初始化方法”
1. 全能初始化方法
*** 概念 ***
可為對(duì)象提供必要信息以便其能完成工作的初始化方法叫做全能初始化方法。
其余的初始化方法都要調(diào)用它,于是,只有在全能初始化方法中,才會(huì)存儲(chǔ)內(nèi)部數(shù)據(jù)。這樣的話,當(dāng)?shù)讓訑?shù)據(jù)存儲(chǔ)機(jī)制改變時(shí),只需修改此方法的代碼就好,無須改動(dòng)其他初始化方法。
2. NSObject類的init方法
當(dāng)NSObject類的子類實(shí)現(xiàn)init方法時(shí),一般有兩種方式:
- 自己指定默認(rèn)的初始值(只適用于簡(jiǎn)單的待初始化數(shù)據(jù))。
- 拋出異常,指明本類實(shí)例必須用“全能初始化方法”來初始化。
3. 例子
/* EOCRectangle頭文件 */
#import <Foundation/Foundation.h>
@interface EOCRectangle : NSObject<NSCoding>
@property(nonatomic, assign, readonly) float width;
@property(nonatomic ,assign, readonly) float height;
- (id)initWithWidth:(float)width andHeight:(float)height;
@end
/* EOCRectangle實(shí)現(xiàn)文件 */
#import "EOCRectangle.h"
@implementation EOCRectangle
// 全能初始化方法
- (id)initWithWidth:(float)width andHeight:(float)height{
if (self = [super init]) { // 先調(diào)用NSObject類的init方法
_width = width;
_height = height;
}
return self;
}
// 覆寫NSObject類的init方法,指定默認(rèn)的值
- (id)init{
return [self initWithWidth:5.0f andHeight:10.0f];
}
// 對(duì)屬性解碼,存放到實(shí)例變量中
- (id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]) { // 先調(diào)用NSObject類的init方法
_width = [decoder decodeFloatForKey:@"width"];
_height = [decoder decodeFloatForKey:@"height"];
}
return self;
}
// 編碼
- (void)encodeWithCoder:(NSCoder *)coder{
[coder encodeFloat:_width forKey:@"width"];
[coder encodeFloat:_height forKey:@"height"];
}
@end
/* EOCSquare頭文件 */
#import "EOCRectangle.h"
@interface EOCSquare : EOCRectangle
- (id)initWithDimension:(float)dimension;
@end
/* EOCSquare實(shí)現(xiàn)文件 */
#import "EOCSquare.h"
@implementation EOCSquare
// 子類的全能初始化方法
- (id)initWithDimension:(float)dimension{
// 調(diào)用父類的全能初始化方法
return [super initWithWidth:dimension andHeight:dimension];
}
// 覆寫父類的全能初始化方法,防止出現(xiàn)長(zhǎng)和寬不等的正方形
- (id)initWithWidth:(float)width andHeight:(float)height{
float dimension = MAX(width, height);
return [self initWithDimension:dimension];
}
// 解碼
- (id)initWithCoder:(NSCoder *)decoder{
if (self = [super initWithCoder:decoder]) {// 先調(diào)用父類的initWithCoder:方法
// 該子類若有新的屬性,需要額外解碼
}
return self;
}
@end
/* main函數(shù) */
#import <Foundation/Foundation.h>
#import "EOCRectangle.h"
#import "EOCSquare.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
EOCRectangle *rectangle = [[EOCRectangle alloc] init];
NSLog(@"rectangle: width = %.1f, height = %.1f",rectangle.width, rectangle.height);
EOCRectangle *rectangle2 = [[EOCRectangle alloc] initWithWidth:3.2 andHeight:4.6];
NSLog(@"rectangle2: width = %.1f, height = %.1f",rectangle2.width, rectangle2.height);
EOCSquare *square = [[EOCSquare alloc] init];
NSLog(@"square: width = %.1f, height = %.1f",square.width, square.height);
EOCSquare *square2 = [[EOCSquare alloc] initWithDimension:4.5];
NSLog(@"square2: width = %.1f, height = %.1f",square2.width, square2.height);
}
return 0;
}
輸出結(jié)果:
rectangle: width = 5.0, height = 10.0
rectangle2: width = 3.2, height = 4.6
square: width = 10.0, height = 10.0
square2: width = 4.5, height = 4.5
要點(diǎn)
- 在類中提供一個(gè)全能初始化方法,并于文檔里指明。其他初始化方法均調(diào)用此方法。
- 若全能初始化方法與超類不同,則需覆寫超類中的對(duì)應(yīng)方法。
- 如果超類的初始化方法不適用于子類,那么應(yīng)該覆寫這個(gè)超類方法,并在其中拋出異常。