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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1287950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:05:34  来源:igfitidea点击:

In Objective-C why should I check if self = [super init] is not nil?

objective-cnullinit

提问by Jasarien

I have a general question about writing init methods in Objective-C.

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

I see it everywhere (Apple's code, books, open source code, etc.) that an init method should check if self = [super init] is not nil before continuing with initialisation.

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

The default Apple template for an init method is:

init 方法的默认 Apple 模板是:

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

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

    return self;
}

Why?

为什么?

I mean when is init ever going to return nil? If I called init on NSObject and got nil back, then something must be really screwed, right? And in that case, you might as well not even write a program...

我的意思是 init 什么时候会返回 nil?如果我在 NSObject 上调用 init 并返回 nil,那么一定是真的搞砸了,对吧?在这种情况下,您甚至可能不编写程序......

Is it really that common that a class' init method may return nil? If so, in what case, and why?

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

采纳答案by iKenndac

For example:

例如:

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

... and so on. (Note: NSData might throw an exception if the file doesn't exist). There are quite a few areas where returning nil is the expected behaviour when a problem occurs, and because of this it's standard practice to check for nil pretty much all the time, for consistency's sake.

... 等等。(注意:如果文件不存在,NSData 可能会抛出异常)。有很多地方在出现问题时返回 nil 是预期的行为,因此,为了一致性,几乎一直检查 nil 是标准做法。

回答by bbum

This particular idiom is standard because it works in all cases.

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

While uncommon, there will be cases where...

虽然不常见,但也会有这样的情况...

[super init];

... returns a different instance, thus requiring the assignment to self.

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

And there will be cases where it will return nil, thus requiring the nil check so that your code doesn't try to initialize an instance variable slot that no longer exists.

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

The bottom line is that it is the documented correct pattern to use and, if you aren't using it, you are doing it wrong.

最重要的是,它是记录在案的正确使用模式,如果您不使用它,那么您就做错了。

回答by Gino

I think, in most classes, if the return value from [super init] is nil and you check it, as recommended by standard practices, and then return prematurely if nil, basically your app is still not going to work correctly. If you think about it, even though that if (self != nil) check is there, for proper operation of your class, 99.99% of the time you actually doneed self to be non-nil. Now, suppose, for whatever reason, [super init] didreturn nil, basically your check against nil is basically passing the buck up to the caller of your class, where it would likely fail anyways, since it will naturally assume that the call was successful.

我认为,在大多数类中,如果 [super init] 的返回值是 nil 并且您按照标准实践的建议检查它,然后如果 nil 则过早返回,基本上您的应用程序仍然无法正常工作。如果您考虑一下,即使存在 if (self != nil) 检查,为了您的类的正确操作,99.99% 的时间您实际上确实需要 self 为非 nil。现在,假设,无论出于何种原因,[super init]确实返回了 nil,基本上您对 nil 的检查基本上是将费用传递给您班级的调用者,无论如何它都可能会失败,因为它自然会假设调用是成功的。

Basically, what I'm getting at is that 99.99% of the time, the if (self != nil) does not buy you anything in terms of greater robustness, since you're just passing the buck up to your invoker. To really be able to handle this robustly, you would actually need to put in checks in your entire calling hierarchy. And even then, the only thing it would buy you is that your app would fail a little more cleanly/robustly. But it would still fail.

基本上,我的意思是,在 99.99% 的情况下, if (self != nil) 并没有为您带来更大的稳健性,因为您只是将责任推给了您的调用者。为了真正能够稳健地处理这个问题,您实际上需要在整个调用层次结构中进行检查。即便如此,它能给你带来的唯一好处就是你的应用程序会更干净/更健壮地失败。但它仍然会失败。

If a library class arbitrarily decided to return nil as a result of a [super init], you're pretty much f***ed anyways, and that's more of an indication that the writer of the library class made a mistake of implementation.

如果一个库类因为 [super init] 任意决定返回 nil,那么无论如何你都会被吓到,这更表明库类的作者在实现上犯了一个错误。

I think this is more of a legacy coding suggestion, when apps ran in much more limited memory.

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

But for C level code, I would still typically check the return value of malloc() against a NULL pointer. Whereas, for Objective-C, until I find evidence to the contrary, I think I'll generally skip the if (self != nil) checks. Why the discrepancy ?

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

Because, at the C and malloc levels, in some cases you actually can partially recover. Whereas I think in Objective-C, in 99.99% of cases, if [super init] does return nil, you're basically f***ed, even if you try to handle it. You might as well just let the app crash and deal with the aftermath.

因为,在 C 和 malloc 级别,在某些情况下,您实际上可以部分恢复。而我认为在 Objective-C 中,在 99.99% 的情况下,如果 [super init] 确实返回 nil,那么即使您尝试处理它,您基本上也被搞砸了。您不妨让应用程序崩溃并处理后果。

回答by user123444555621

This is kind of a summary of the comments above.

这是上面评论的总结。

Let's say the superclass returns nil. What's gonna happen?

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

If you don't follow the conventions

如果你不遵守约定

Your code is gonna crash in the middle of your initmethod. (unless initdoes nothing of significance)

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

If you follow the conventions, not knowing that the superclass might return nil (most people end up here)

如果你遵循约定,不知道超类可能会返回 nil(大多数人最终会在这里)

Your code is probalby gonna crash at some point later, because your instance is nil, where you expected something different. Or your program is gonna behave unexpectedly without crashing. Oh dear! Do you want this? I don't know...

您的代码可能会在稍后的某个时间崩溃,因为您的实例是nil,您期望有所不同。或者你的程序会意外运行而不会崩溃。哦亲爱的!你想要这个吗?我不知道...

If you follow the conventions, willingly allowing your subclass to return nil

如果你遵循约定,愿意让你的子类返回 nil

Your code documentation(!) should clearly state: "returns ... or nil", and the rest of your code needs to be prepared for handling this. Now it makes sense.

您的代码文档(!)应该清楚地说明:“返回 ... 或 nil”,并且您的其余代码需要准备好处理这个问题。现在说得通了。

回答by John Rudy

Typically, if your class derives directly from NSObject, you won't need to. However, it's a good habit to get into, as if your class derives from other classes, their initializers may return nil, and if so, your initializer can then capture that and behave correctly.

通常,如果您的类直接从 派生NSObject,则不需要。但是,养成一个好习惯,就好像您的类派生自其他类一样,它们的初始化程序可能会返回nil,如果是这样,您的初始化程序可以捕获它并正确运行。

And yes, for the record, I follow the best practice and write it on all my classes, even those deriving directly from NSObject.

是的,作为记录,我遵循最佳实践并将其写在我所有的类上,即使是那些直接从NSObject.

回答by andyvn22

You're right, you could often just write [super init], but that wouldn't work for a subclass of just anything. People prefer to just memorize one standard line of code and use it all the time, even when it's only sometimes necessary, and thus we get the standard if (self = [super init]), which takes both the possibility of nil being returned and the possibility of an object other than selfbeing returned into account.

你是对的,你通常可以只写[super init],但这对任何东西的子类都不起作用。人们更愿意只记住一个标准的代码行,并用它所有的时间,即使它只是有时必要的,因此,我们得到的标准if (self = [super init]),这需要的零返回两者的可能性和对象比其他的可能性self正在返回考虑到。

回答by Chris Reid

A common mistake is to write

一个常见的错误是写

self = [[super alloc] init];

which returns an instance of the superclass, which is NOT what you want in a subclass constructor/init. You get back an object that does not respond to the subclass methods, which can be confusing, and generate confusing errors about not reponding to methods or identifiers not found, etc.

它返回超类的一个实例,这不是您在子类构造函数/init 中想要的。你得到一个不响应子类方法的对象,这可能会令人困惑,并产生关于不响应方法或未找到标识符等的混淆错误。

self = [super init]; 

is needed if the super class has members (variables or other objects) to initialize firstbefore setting up the subclasses' members. Otherwise the objc runtime initializes them all to 0or to nil. (unlike ANSI C, which often allocates chunks of memory without clearing them at all)

需要如果超类有成员(变量或其他对象)来初始化第一建立子类成员之前。否则 objc 运行时会将它们全部初始化为0nil。(与 ANSI C 不同,ANSI C 经常分配内存块而不清除它们

And yes, base class initialization can fail because of out-of-memory errors, missing components, resource acquisition failures, etc. so a check for nil is wise, and takes less than a few milliseconds.

是的,基类初始化可能会因为内存不足错误、缺少组件、资源获取失败等原因而失败。所以检查 nil 是明智的,并且花费的时间不到几毫秒。

回答by Daniel

This is to check that the intialazation worked, the if statement returns true if the init method did not return nil, so its a way to check creation of the object worked correctly. Few reasons i can think of that init might fail maybe its an overriden init method that the super class does not know of or something of the sort, I wouldnt think it is that common though. But if it does happen, its better nothing to happen that a crash i supose so its always checked...

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

回答by MaddTheSane

In OS X, it's not as likely for -[NSObject init]to fail due to memory reasons. The same cannot be said for iOS.

在 OS X 中,不太可能-[NSObject init]由于内存原因而失败。对于 iOS 则不能这样说。

Also, it's good practice for writing when subclassing a class that might return nilfor whatever reason.

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