前言 :在苹果的开发文档中我们发现 NSDate 这个类的初始方法:
- (instancetype)initNS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)tiNS_DESIGNATED_INITIALIZER;
- (nullableinstancetype)initWithCoder:(NSCoder *)aDecoderNS_DESIGNATED_INITIALIZER;
+ (instancetype)date;
+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
+ (instancetype)dateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti;
+ (instancetype)dateWithTimeIntervalSince1970:(NSTimeInterval)secs;
+ (instancetype)dateWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)date;
那么这些初始化方法之间的关系是怎样的呢? 还是说毫无关联。其实它们都使用了一个共同的初始化方法- (instancetype)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti NS_DESIGNATED_INITIALIZER; 我们可以使用NSRuntime 进去看看最终都会进入
这个初始化方法。我们把这个方法称为全能初始化方法。 这里就不介绍NSRuntime了。 那么apple 为什么要这样做呢?,在实际开发过程中我们应当如何使用和注意呢?
二: 实际使用
每个子类的全能初始化方法都应该调用起超类的对应的方法.并逐层向上。当底层数据存储机制改变时,只需修改此方法的代码就好.无需改动其他的初始化方法而且能减少消息的转发带来的消耗
新建类
@interface EOCRectangle : NSObject<NSCoding>
@property (nonatomic,assign,readonly)float width;
@property (nonatomic,assign,readonly)float height;
- (instancetype)initWithWidth:(float) width
andHeight:(float )height;
@end
- (instancetype)initWithWidth:(float) width
andHeight:(float )height
{
NSLog(@"rectangle init initWithWidthAndHeight");
if (self=[superinit]) {
_width=width;
_height=height;
}
returnself;
}
/*
但是开发者有可能直接调用了 init 方法 因为NSObject 是实现了init方法了的
*/
- (instancetype)init
{
NSLog(@"rectangle init ");
return [selfinitWithWidth:5.0f andHeight:10.0f];
}
当然如果你不写的话会使用默认的0 来代替 这样的长方形显然没有实际的意义。 但是如果你使用新的类 EOCSquare 继承自EOCRectangle
我们要求长和宽都相等。
@interface EOCSquare : EOCRectangle
- (instancetype)initWithDimension:(float)dimension;
@end
// 即时默认的 init方法 也要重写我们可以想象如果 没有重写会
// 调用其父类的 initWithWidth 方法生成的 10 5 的正方形的例子
-(instancetype)init
{
return [selfinitWithDimension:5.0f];
}
- (instancetype)initWithDimension:(float)dimension
{
NSLog(@"square initWith dimension ---");
return [superinitWithWidth:dimension andHeight:dimension];
}
// 很有可能用户会调用 initWithWidth andHeight方法
// 我们需要保证 square正方形 的 width和 height 是一致的
- (instancetype)initWithWidth:(float)width andHeight:(float)height
{
NSLog(@"square init width and height ");
float dimension=MAX(width, height);
return [selfinitWithDimension:dimension];
}
其次要特别注意 NSCoding 这个地方
#pragma mark ---- initializer from NSCoding
在 EOCRectangle 中要这样写
/**
从 NSCoding协议 序列化
@param aDecoder aDecoder description
@return return value description
*/
/*
!!!!
NSCoding 协议的初始化方法没有调用本类的全能初始化方法
而是调用了超类的相关方法而且若超类 也实现了了NSCoding,
则改为调用调用超类的 initWithCoder: 初始化方法
*/
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self=[superinit]) {
_width=[aDecoderdecodeFloatForKey:@"width"];
_height=[aDecoderdecodeFloatForKey:@"height"];
}
returnself;
}
在 EOCSquare 中要这样写
#pragma mark ---- NSCoding
/*
!!! 由于父类中写了这个 initWithCoder 方法
所以我们
initCoder 中也要遵守NSCoding协议 如果没有调用超类的同名方法.而是调用了自制的初始化方法
或者超类的其他初始化方法 .那么EOCRectangle类的initWithCoder 方法就没机会执行
于是 无法将 _width 和 _height这两个实例 变量解码了
*/
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self=[superinitWithCoder:aDecoder]) {
}
returnself;
}
大概的意思就是这样了。