是否声明每个对象创建成功在Objective C中是必要的? [英] Is asserting that every object creation succeeded necessary in Objective C?

查看:157
本文介绍了是否声明每个对象创建成功在Objective C中是必要的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近阅读Apple的开发人员撰写的 MVCNetworking 的Apple示例代码技术支持guru Quinn爱斯基摩!样本是真正好的学习经验,我猜是iOS开发的最佳开发实践。
来自JVM语言的令我惊讶的是非常频繁的断言:

  syncDate = [NSDate date] ; 
assert(syncDate!= nil);

并且:

  photosToRemove = [NSMutableSet setWithArray:knownPhotos]; 
assert(photosToRemove!= nil);

并且:

  photoIDToKnownPhotos = [NSMutableDictionary dictionary]; 
assert(photoIDToKnownPhotos!= nil);

这真的有必要吗?这种编码风格值得仿效吗?

解决方案

如果你习惯Java,这可能看起来很奇怪。你会期望一个对象创建消息失败时抛出异常,而不是返回 nil 。但是, Mac OS X上的Objective-C支持异常处理;它是一个可选特性,可以使用编译器标志打开/关闭。标准库被编写,所以它们可以在没有异常处理的情况下使用:因此消息通常返回 nil 以指示错误,有时需要你还传递一个指针到 NSError * 变量。 (这是为Mac开发,我不知道你是否甚至可以打开iOS上的异常处理支持,考虑你也不能打开iOS的垃圾回收。)



部分处理初始化失败解释了Objective-C程序员如何处理对象初始化/创建中的错误: nil



[NSData dataWithContentsOfFile:path] 可以肯定地返回 nil :方法的文档明确说如此。但我真的不知道像 [NSMutableArray arrayWithCapacity:n] 是否返回 nil 。我可以想到的唯一情况是可能是当应用程序内存不足。但在这种情况下,我希望应用程序被尝试分配更多的内存中止。我没有检查这个,但很可能是在这种情况下返回 nil 。而在Objective-C中,您通常可以安全地发送邮件到 nil ,这可能会导致不良结果。例如,您的应用程序可能会尝试创建 NSMutableArray ,获取 nil ,然后愉快地继续发送 addObject: nil ,并写出一个空文件到磁盘,而不是一个数组的元素。因此,在某些情况下,最好明确检查消息的结果是否 nil 。是否需要在个对象创建,像你正在引用的程序员,我不知道。

编辑:我想补充一点,在检查对象创建成功有时可能是一个好主意,断言它可能不是最好的主意。你希望这也被检查在应用程序的发布版本,而不仅仅是在调试版本。否则会因为你不想让应用程序的最终用户来处理空文件,因为 [NSMutableArray arrayWithCapacity:n] 返回 nil ,应用程序继续向 nil 返回值发送消息。断言(使用 assert NSAssert ) Xcode似乎没有包括这些标志在默认情况下在发布配置。但是如果你想使用这些标志来删除一些其他的断言,你也会删除你所有的对象创建成功检查。



编辑:经进一步反思,看起来似乎比我最初认为 [NSMutableArray arrayWithCapacity:n] 会返回 nil 而不是在没有足够的内存可用时中止应用程序。当没有足够的内存可用时,基本C malloc 也不中止,但返回 NULL 指针。但我还没有发现在Objective-C文档中有关于 alloc 和类似方法。



编辑:上面我说我不确定检查 nil 。但它不应该。这正是为什么Objective-C允许发送消息到 nil ,然后返回 nil (或 0 或类似的东西,取决于消息定义):这样, nil 可以传播通过你的代码有点类似于一个异常, 必须在可能返回的每个邮件中显式检查 nil 。但是它是一个好主意,以检查它在你不希望它传播的点,如当写入文件,与用户等交互,或在发送消息的结果到 nil 未定义(如关于向 nil 发送邮件的文档)。我倾向于说这就像是穷人的异常传播和处理版本,虽然不是每个人都同意后者是更好的;但是 nil 不会告诉你为什么会发生错误,你可以很容易忘记检查是否需要这样的检查。


I have recently read Apple's sample code for MVCNetworking written by Apple's Developer Technical Support guru Quinn "The Eskimo!". The sample is really nice learning experience with what I guess are best development practices for iOS development. What surprised me, coming from JVM languages, are extremely frequent assertions like this:

syncDate = [NSDate date];
assert(syncDate != nil);

and this:

photosToRemove = [NSMutableSet setWithArray:knownPhotos];
assert(photosToRemove != nil);

and this:

photoIDToKnownPhotos = [NSMutableDictionary dictionary];
assert(photoIDToKnownPhotos != nil);

Is that really necessary? Is that coding style worth emulating?

解决方案

If you're used to Java, this may seem strange. You'd expect an object creation message to throw an exception when it fails, rather than return nil. However, while Objective-C on Mac OS X has support for exception handling; it's an optional feature that can be turned on/off with a compiler flag. The standard libraries are written so they can be used without exception handling turned on: hence messages often return nil to indicate errors, and sometimes require you to also pass a pointer to an NSError* variable. (This is for Mac development, I'm not sure whether you can even turn exception handling support on for iOS, considering you also can't turn on garbage collection for iOS.)

The section "Handling Initialization Failure" in the document "The Objective-C Programming Language" explains how Objective-C programmers are expected to deal with errors in object initialization/creation: that is, return nil.

Something like [NSData dataWithContentsOfFile: path] may definitely return nil: the documentation for the method explicitly says so. But I'm honestly not sure whether something like [NSMutableArray arrayWithCapacity: n] ever returns nil. The only situation I can think of when it might is when the application is out of memory. But in that case I'd expect the application to be aborted by the attempt to allocate more memory. I have not checked this though, and it may very well be that it returns nil in this case. While in Objective-C you can often safely send messages to nil, this could then still lead to undesirable results. For example, your application may try to make an NSMutableArray, get nil instead, and then happily continue sending addObject: to nil and write out an empty file to disk rather than one with elements of the array as intended. So in some cases it's better to check explicitly whether the result of a message was nil. Whether doing it at every object creation is necessary, like the programmer you're quoting is doing, I'm not sure. Better safe than sorry perhaps?

Edit: I'd like to add that while checking that object creation succeeded can sometimes be a good idea, asserting it may not be the best idea. You'd want this to be also checked in the release version of your application, not just in the debug version. Otherwise it kind of defeats the point of checking it, since you don't want the application end user to, for example, wind up with empty files because [NSMutableArray arrayWithCapacity: n] returned nil and the application continued sending messages to the nil return value. Assertions (with assert or NSAssert) can be removed from the release version with compiler flags; Xcode doesn't seem to include these flags by default in the "Release" configuration though. But if you'd want to use these flags to remove some other assertions, you'd also be removing all your "object creation succeeded" checks.

Edit: Upon further reflection, it seems more plausible than I first thought that [NSMutableArray arrayWithCapacity: n] would return nil rather than abort the application when not enough memory is available. Basic C malloc also doesn't abort but returns a NULL pointer when not enough memory is available. But I haven't yet found any clear mention of this in the Objective-C documentation on alloc and similar methods.

Edit: Above I said I wasn't sure checking for nil is necessary at every object creation. But it shouldn't be. This is exactly why Objective-C allows sending messages to nil, which then return nil (or 0 or something similar, depending on the message definition): this way, nil can propagate through your code somewhat similar to an exception so that you don't have to explicitly check for nil at every single message that might return it. But it's a good idea to check for it at points where you don't want it to propagate, like when writing files, interacting with the user and so on, or in cases where the result of sending a message to nil is undefined (as explained in the documentation on sending messages to nil). I'd be inclined to say this is like the "poor man's" version of exception propagation&handling, though not everyone may agree that the latter is better; but nil doesn't tell you anything about why an error occurred and you can easily forget to check for it where such checks are necessary.

这篇关于是否声明每个对象创建成功在Objective C中是必要的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆