在Objective-C中,我为什么要检查self = [super init]是不是nil?

时间:2009-08-17 13:25:11

标签: objective-c null init

我有一个关于在Objective-C中编写init方法的一般问题。

我到处都看到它(Apple的代码,书籍,开源代码等)init方法应该在继续初始化之前检查self = [super init]是否为nil。

init方法的默认Apple模板是:

- (id) init
{
    self = [super init];

    if (self != nil)
    {
        // your code here
    }

    return self;
}

为什么?

我的意思是什么时候才能返回nil?如果我在NSObject上调用init并且没有回来,那么一定要搞砸了,对吗?在这种情况下,你甚至可以不写程序......

类的init方法可能返回nil真的很常见吗?如果是这样,在什么情况下,为什么?

9 个答案:

答案 0 :(得分:52)

例如:

[[NSData alloc] initWithContentsOfFile:@"this/path/doesn't/exist/"];
[[NSImage alloc] initWithContentsOfFile:@"unsupportedFormat.sjt"];
[NSImage imageNamed:@"AnImageThatIsntInTheImageCache"];

......等等。 (注意:如果文件不存在,NSData可能会抛出异常)。在发生问题时,有很多区域返回nil是预期的行为,并且由于这个原因,为了保持一致性,几乎一直都要检查nil是标准做法。

答案 1 :(得分:50)

这个特定的习语是标准的,因为它适用于所有情况。

虽然不常见,但仍会出现......

[super init];

...返回一个不同的实例,因此需要赋值给自己。

并且会出现返回nil的情况,因此需要进行nil检查,以便您的代码不会尝试初始化不再存在的实例变量槽。

最重要的是,它是使用的文档正确的模式,如果你不使用它,你做错了。

答案 2 :(得分:25)

我认为,在大多数课程中,如果[super init]的返回值为nil并按照标准惯例的建议进行检查,然后如果为nil则提前返回,基本上你的应用程序仍无法正常工作。 如果你考虑一下,即使if(self!= nil)检查在那里,为了你班级的正常运作,你实际上的99.99%的时间需要自己是非零的。 现在,假设,无论出于何种原因,[super init] 确实返回nil,基本上你对nil的检查基本上是将你的责任传递给你的类的调用者,在那里它可能会失败,因为它将自然地假设呼叫成功。

基本上,我所得到的是99.99%的时间,if(self!= nil)并没有为你提供更强大的东西,因为你只是把责任推到你的调用者身上。要真正能够强有力地处理这个问题,您实际上需要在整个调用层次结构中进行检查。即便如此,它唯一能给你买的是你的应用程序会更加干净/健壮地失败。但它仍然会失败。

如果一个库类任意决定由于[super init]而返回nil,那么你几乎已经被删除了,这更多地表明了库类的作者犯了一个错误实施。

我认为当应用程序在更有限的内存中运行时,这更像是一种遗留的编码建议。

但是对于C级代码,我仍然通常会检查malloc()的返回值是否为NULL指针。然而,对于Objective-C,直到我找到相反的证据,我想我通常会跳过if(self!= nil)检查。为什么会出现差异?

因为,在C和malloc级别,在某些情况下,您实际上可以部分恢复。虽然我认为在Objective-C中,在99.99%的情况下,如果[super init]确实返回nil,那么即使你试图处理它,你也基本上都是f *** ed。您可能只是让应用程序崩溃并处理后果。

答案 3 :(得分:8)

这是上述评论的总结。

假设超类返回nil。会发生什么事?

如果您不遵守惯例

您的代码会在init方法的中间崩溃。 (除非init没有任何意义)

如果你遵循惯例,不知道超类可能会返回nil(大多数人都会在这里结束)

你的代码是probalby稍后会崩溃,因为你的实例是nil,你期望有不同的东西。或者你的程序会出现意外行为而不会崩溃。噢亲爱的!你想要这个吗?我不知道......

如果您遵循惯例,愿意允许您的子类返回nil

您的代码文档(!)应明确说明:“return ...或nil”,其余代码需要为处理此代码做好准备。 现在它是有道理的。

答案 4 :(得分:7)

通常,如果您的班级直接来自NSObject,则您不需要。但是,这是一个很好的习惯,就好像你的类来自其他类,它们的初始值设定项可能会返回nil,如果是这样,你的初始化程序就可以捕获它并且行为正确。

是的,为了记录,我遵循最佳实践并将其写在我的所有课程上,甚至是那些直接来自NSObject的课程。

答案 5 :(得分:3)

你是对的,你可以经常写[super init],但这对任何事物的子类都不起作用。人们更喜欢只记住一行标准代码并一直使用它,即使它只是有时是必要的,因此我们得到标准的if (self = [super init]),它既可以返回nil,也可以使用nil。除了self以外的对象被重新考虑。

答案 6 :(得分:3)

常见的错误是写

self = [[super alloc] init];

返回超类的实例,这不是你想要的子类构造函数/ init。 你得到一个不响应子类方法的对象,这可能会让人感到困惑,并且会产生令人困惑的错误,因为它们没有找到未找到的方法或标识符等等。

self = [super init]; 
如果超类在成立子类的成员之前有成员(变量或其他对象)初始化 ,则需要

。否则,objc运行时将它们全部初始化为 0 nil 。 (与ANSI C不同,后者经常分配内存块而根本不清除它们

是的,基类初始化可能会由于内存不足错误,组件丢失,资源获取失败等原因而失败,因此检查nil是明智的,并且需要不到几毫秒。

答案 7 :(得分:2)

这是为了检查intialazation是否有效,if语句如果init方法没有返回nil则返回true,因此它检查对象的创建是否正常工作。很少有理由我可以想到init可能会失败,也许它是一个超类初始化方法,超类不知道或类似的东西,我不认为这是常见的。但是,如果它确实发生了,那么最好不要发生碰撞,因为它总是被检查......

答案 8 :(得分:1)

在OS X中,由于内存原因-[NSObject init]失败的可能性不大。对于iOS来说也是如此。

此外,在对可能因任何原因返回nil的类进行子类化时,写入是一种很好的做法。