为什么在消息nil无效时检查self!= nil in -init?

时间:2012-08-17 07:14:11

标签: objective-c

假设我们的-init方法仅调用self上的消息,为什么在self != nil消息无效后检查nil是否常见?

假设我们有一个初始化程序如下:

- (id)init
{
    self = [super init];
    if (self) {
        [self doThis];
        [self setFoo:@"Bar"];
    }

    return self;
}

我们可以写下:

,而不是检查self
- (id)init
{
    self = [super init];
    [self doThis];
    [self setFoo:@"Bar"];

    return self;
}

现在,如果出于某种原因[super init]返回nil,那么据我所知,该方法的结果没有差异。为什么我们会不断执行此检查?

2 个答案:

答案 0 :(得分:7)

您可以向nil发送消息,但无法访问nil的实例变量。您将获得EXC_BAD_ACCESS例外。

考虑一个具有实例变量的类:

@implementation MyObject {
    int instanceVariable;
}

- (id)init {
    self = [super init];
    instanceVariable = 7;
    return self;
}

如果[super init]在此示例中返回nil会发生什么? instanceVariable并获得异常。

即使您没有访问任何实例变量,如果您不检查self == nil,其他事情肯定会出错。您可以轻松地泄漏malloc - 已分配的内存或文件句柄,或者将自己传递给某些不期望为零的方法。

其他答案声称,如果您不检查零,则可以泄漏对象。例如:

@implementation MyObject

@synthesize someProperty; // assume it's an NSObject *

- (id)init {
    self = [super init];
    [self setSomeProperty:[[NSObject alloc] init]];
    return self;
}

即使self为零,这也不会在ARC下泄露。在手动引用计数(MRC)下,此示例将泄漏self是否为零,因为没有任何内容可以平衡来自[NSObject alloc]的+1保留计数。

在MRC下进行此操作的正确方法是:

- (id)init {
    self = [super init];
    [self setSomeProperty:[[[NSObject alloc] init] autorelease]];
}

或者这个:

- (id)init {
    self = [super init];
    NSObject *object = [[NSObject alloc] init];
    [self setSomeProperty:object];
    [object release];
    return self;
}

无论self是否为零,都不会泄漏。

如果你绕过setter方法,就像这样,如果self为零,你就会崩溃:

- (id)init {
    self = [super init];
    _someProperty = [[NSObject alloc] init];
    return self;
}

答案 1 :(得分:0)

如果[super init]反过来返回nil,那么你最终可能会分配更多永远不会被使用的对象,因为当你返回self时,你将返回nil;所以这些对象不会被释放。