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

fph*_*ipe 6 objective-c

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

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

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

    return self;
}
Run Code Online (Sandbox Code Playgroud)

self我们可以写下:而不是检查:

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

    return self;
}
Run Code Online (Sandbox Code Playgroud)

现在如果由于某种原因[super init]返回nil,据我所知,该方法的结果没有区别.为什么我们会经常执行此检查?

rob*_*off 7

您可以将消息发送到nil,但是您无法访问nil的实例变量.你会得到一个EXC_BAD_ACCESS例外.

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

@implementation MyObject {
    int instanceVariable;
}

- (id)init {
    self = [super init];
    instanceVariable = 7;
    return self;
}
Run Code Online (Sandbox Code Playgroud)

如果[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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

- (id)init {
    self = [super init];
    [self setSomeProperty:[[[NSObject alloc] init] autorelease]];
}
Run Code Online (Sandbox Code Playgroud)

或这个:

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

这些都不会泄漏,无论是否self为零.

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

- (id)init {
    self = [super init];
    _someProperty = [[NSObject alloc] init];
    return self;
}
Run Code Online (Sandbox Code Playgroud)