2012-08-17 47 views
6

假设我们的-init方法仅调用self上的消息,为什么通常要检查消息nil是否不起作用self != nil为什么在消息nil无效时检查self!= nil in -init?

比方说,我们有一个初始化如下:

- (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,不会有什么区别在我所知的方法的结果中。为什么我们会不断地执行这项检查?

回答

7

您可以发送消息给nil,但不能访问nil的实例变量。你会得到一个EXC_BAD_ACCESS例外。

考虑一个实例变量的类:

@implementation MyObject { 
    int instanceVariable; 
} 

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

如果[super init]回报在这个例子中无会发生什么?您将尝试从空指针访问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; 
} 

这不会在ARC下泄漏,即使self为零。在手动引用计数(MRC),这个例子将泄漏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是零:

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

这是相当的信号 - C没有异常。 – 2012-08-17 07:24:09

+1

+1虽然,很好的答案。 – 2012-08-17 07:27:39

+0

这是一个CPU异常,而不是C++异常。查看'/ usr/include/mach/exception_types.h'。 – 2012-08-17 07:29:18

0

如果[超级初始化]又回零做到了,那么你最终将有可能分配更多永远不会使用的对象,因为当你返回自己的时候,你将返回零;所以这些对象不会被释放。

+0

最后@rob是对的 - 这不是真正的原因。 – 2012-08-17 07:27:24

+0

@ user1606088虽然不要气馁。这是一个非常微妙的问题。 – 2012-08-17 07:38:35

相关问题