由于各种各样的后续从返回nil [类的alloc]初始化]好的做法? ,还有,我还没有看到任何讨论很多的情况下:如何处理失败了一些先决条件,才可以调用初始化旁边一个init?
例如,假设在此initWithStuff:传递零或一般没有价值传递给initWithValue方法:是一个绝对的失败,我们一定要回到零。
- (id)initWithStuff:(Stuff *)inStuff {
if (!inStuff || ![inStuff hasValidValue])
{
// can't proceed to call initWithValue: because we have no value
// so do what?
return nil;
}
NSInteger value = [inStuff integerValue];
return [super initWithValue:value];
}
也许更清楚的例子是,如果我们包裹指定初始化方法采用一个对象的指针,并抛出如果其通过零个例外。 我们一定要到初始化调用会导致异常短路。
我的猜测:任何初始化可能的手段,然后才返回nil之前释放自我。 如有必要,呼叫裸init或任何其他初始化,将工作完成把自成已知状态释放之前。
// can't proceed to call super's initWithValue: because we have no value
// so do what? do this:
self = [super init]; // or initWithValue:0
[self release];
return nil;
如果没有这样的初始化,将没有有效数据的工作,我想人们会需要构建一些有效的,虚拟数据。 或者抱怨它的作者,直到然后就返回零,并与泄漏住:^)
此外,如何ARC影响的情况呢?
我的猜测:仍然完成任何初始化可能的手段,那么就返回nil。 你会觉得自己的设置可能是多余的,但在某些情况下,它不是。 在任何情况下,但它需要在那里沉默编译器警告。
// can't proceed to call super's initWithValue: because we have no value
// so do what? do this:
self = [super init]; // finish init so ARC can release it having no strong references
return nil;
是我猜错以任何方式?
理想情况下,如果前提条件失败,你不叫[super init…]
你只要释放self
(如果不使用ARC),并返回零:
- (id)initWithStuff:(Stuff *)stuff {
if (!stuff || ![stuff isValid]) {
[self release]; // if not using ARC
return nil;
}
if (self = [super init]) {
// initialization here
}
return self;
}
发布需要重新分配照顾self
MRC下。 根据ARC,编译器会插入你释放。
但是,这种方法的潜在问题。 当你释放self
(或当ARC释放它为你)时,系统将发送dealloc
消息的对象。 和你dealloc
方法将调用[super dealloc]
你可以抑制[super dealloc]
MRC下,但你不能用ARC避免。
所以危险的是,你的超可能会认为它的实例变量中的一个已经初始化,并依靠其是初始值dealloc
。 例如,假设这是超:
@interface SomeSuperclass : NSObject
@end
@implementation SomeSuperclass {
CFMutableBagRef bag;
}
- (id)init {
if (self = [super init]) {
bag = CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks);
}
return self;
}
- (void)dealloc {
CFRelease(bag);
}
@end
这里的问题是, CFRelease
要求其参数不为零。 因此,这将释放过程中崩溃,如果你不叫[super init]
在你的子类。
考虑到这个问题,我不得不改变我最初的建议。 如果你知道你的超类的dealloc
没有这类问题(因为,例如,它取消引用或将它们传递到之前检查指针CFRelease
),那么你可以放心地不能调用[super init]
如果你不知道你的超类的dealloc
是安全的,那么我的建议是,你移动你的前提出来的init
,进入一个类工厂方法。
换句话说,不把alloc/init
为你的类的公共接口的一部分。 为创建实例的类方法:
// The class factory method. Declare this in your header file. This is how you
// or any user of this class should create instances.
+ (id)myObjectWithStuff:(Stuff *)stuff {
if (!stuff || ![stuff isValid])
return nil;
// self here is the class object, so it's appropriate to send `alloc` to it.
// You don't want to hardcode the class name here because that would break
// subclassing.
return [[self alloc] initWithStuff:stuff];
}
// This is now considered a private method. You should not declare it in your
// header file, though in Objective-C you can't prevent the user from calling it
// if he's determined to.
- (id)initWithStuff:(Stuff *)stuff {
// Precondition was already checked in myObjectWithStuff:.
if (self = [super init]) {
// initialization here...
}
return self;
}