6

假设我们的-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,据我所知,该方法的结果将没有区别。那么为什么我们要不断地进行这种检查呢?

4

2 回答 2

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分配的内存或文件句柄,或者将自己传递给一些不期望为零的方法。

其他答案声称,如果您不检查 nil,您可能会泄漏对象。例如:

@implementation MyObject

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

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

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

在 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为 nil,你就会崩溃:

- (id)init {
    self = [super init];
    _someProperty = [[NSObject alloc] init];
    return self;
}
于 2012-08-17T07:22:17.750 回答
0

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

于 2012-08-17T07:22:35.740 回答