ios - 在Swift中,如何避免同时使用 optional 对象和nil对象引用?

标签 ios macos swift optional

optional 参数的全部原因是为了防止由于运行时分配给nil/null/none的变量而导致崩溃。因此,变量不能为零。而是可以将它们包装为Optional类型,将它们表示为Some或None,并展开以获取Some或nil的特定内容。

但是,如果您使用!或Implicitly Unwrapped Optionals在所有位置将它们解包,则由于您是一个不完善的编码器,您只会引入运行时崩溃的可能性。如果使用if let安全地解包它们,可以避免崩溃,但是您会陷入if let语句的作用域中,无法使用Some中的值,并且仍然必须处理可能的nil情况。如果使用?为了暂时解开包装以调用方法,完成后将被重新包装,从而引入了多层 optional 包装的困惑可能性。

所以:在我看来,要做的是避免使用 optional 参数,除非必要(例如在调用返回它们的框架方法时)。但是,如果我不使用 optional 参数,则意味着我的对象引用必须为非零,并且我无法弄清楚如何处理由于某种原因而不应该存在或不存在的情况,是分配给对象引用的值。

我的问题是:如何避免不需要零钱?似乎需要不同的编程方法。 (或者我应该只使用 optional 参数,如果这就是我正在做的事情,那比简单地对对象引用像其他语言那样对对象引用进行空赋值有什么好处呢?)

我知道这可能是一个主观的问题,但是我还应该问什么呢?我并不想引发争论,我真的想知道在编写更多Swift代码时正确的方法是什么。

最佳答案

没错,选填项可能会让人感到痛苦,这就是为什么您不应该过度使用它们的原因。但是,它们不仅仅是使用框架时必须处理的事情。它们是对一个非常常见的问题的解决方案:如何处理一个调用,该返回的结果可能是正确的,也可能不是。

例如,以Array.first成员。这是一个方便的实用程序,可为您提供数组的第一个元素。当您只可以调用a.first时,为什么可以调用a[0]有用呢?因为在运行时数组可能为空,所以a[0]会爆炸。当然,您可以事先检查a.count-然后再检查一次

a. you might forget,

and

b. that results in quite ugly code.


Array.first通过返回一个 optional 值来处理此问题。因此,在使用作为数组第一个元素的值之前,您必须先打开 optional 包装。

现在,您的问题是关于untapped值仅存在于if let的块中。想象一下并行代码,检查数组计数。会一样吧?
if a.count > 0 {
    // use a[0]
}
// outside the block, no guarantee
// a[0] is valid

if let firstElement = a.first {
    // use firstElement
}
// outside the block, you _can't_
// use firstElement

当然,如果计数为零,则可以执行类似的从函数中尽早返回的操作。这行得通,但是有点容易出错–如果您忘记这样做,或者将其放在没有碰巧的条件语句中怎么办?本质上,您可以使用array.first进行相同的操作:在函数中先检查计数,然后再在array.first!上进行检查。但是!就像是一个信号,请注意,您做的事情很危险,如果代码不完全正确,您将感到遗憾。

optional 选项还有助于使其他选项更美观。假设您要在数组为空的情况下默认使用该值。代替这个:
array.count > 0 ? a[0] : somedefault

你可以这样写:
array.first ?? somedefault

这在几种方面都更好。它把重要的事情放在首位:所需的值是表达式的开始方式,其后是默认值。与三元表达式不同,三元表达式首先用checking表达式击中您,然后是您实际想要的值,然后是默认值。它还更加万无一失-避免输入错误更加容易,而且该错误不会导致运行时爆炸。

再举一个例子:find函数。这将检查值是否在集合中,并返回其位置的索引。但是该值可能不存在于集合中。其他语言可能会通过返回结束索引(该索引不指向某个值,而是指向最后一个值)来处理此问题。这就是所谓的“前哨”值-一个看起来像常规结果的值,但实际上具有特殊含义。与前面的示例一样,在使用结果之前,您必须检查结果是否等于结束索引。但是您必须知道要执行此操作。您必须在doct文件中查找find并确认其工作方式。

通过find返回一个 optional 参数,当您理解 optional 习语时,很自然地会意识到这样做的原因是因为显而易见的原因,结果可能无效。而且,上述关于安全性的所有事情同样适用-您不能无意间忘记并将结果用作索引,因为您必须先将其拆开。

也就是说,您可以过度使用 optional 选项,因为它们是必须检查的负担。这就是为什么数组下标不返回 optional 值的原因-它将导致麻烦,必须不断检查和解开它们,尤其是当您知道所使用的索引有效的事实时(例如,您在在数组的有效索引范围内进行for循环),人们将不断使用!,从而使他们的代码困惑而无济于事。但是随后添加了诸如first和last这样的辅助方法,以覆盖人们确实希望快速执行操作而不必先检查数组大小而又想安全地进行操作的常见情况。

(另一方面,预计 swift 会通过无效的下标来定期访问“快速字典”,这就是为什么其[key]方法确实返回 optional 内容的原因)

如果可以完全避免发生故障的可能性,那就更好了。例如,当filter不匹配任何元素时,它不会返回nil optional 。它返回一个空数组。您可能会说:“显然会。”但是您会惊讶地发现,当某人实际上应该只返回一个空值时,他们经常会返回诸如数组之类的 optional 值。因此,您完全应该说应该避免使用 optional 选项,除非有必要,否则这是完全正确的,这只是一个必要含义的问题。在上面的示例中,我想说它们是必要的,并且是替代方案的更好解决方案。

关于ios - 在Swift中,如何避免同时使用 optional 对象和nil对象引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27622871/

相关文章:

ios - 强制裁剪/从裁剪工具打开开始

android - 移动应用程序中的 Uber OAuth 最佳实践

objective-c - 有没有办法获取 NSBezierPath 对象所有点的 x,y 坐标?

macos - 使用 xamarin 使用 Visual Studio 构建 ios 应用程序,无需 mac 构建主机

django - 在 Mac OS X 上卸载 Django

ios - 呈现 App Store 产品 View Controller 变得不可逆转

swift - 具有多个单元格的 TableView swift

iphone - 绘制带有渐变的图形线

iOS:renderInContext 以 -90 度渲染窗口的内容?

iphone - 使用特定日期将文本保存在 plist 文件中