一尘不染

在Swift中,如何避免同时使用可选对象和nil对象引用?

swift

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

但是,如果您使用!或Implicitly Unwrapped Optionals
到处都将它们解包,那么由于您是一个不完善的编码器,您只会引入运行时崩溃的可能性。如果您使用if let它们来安全地展开包装,可以避免崩溃,但是您会陷入if let语句范围内,无法使用Some中的值,并且仍然必须处理潜在的nil情况。如果使用?为了临时解包以调用方法,完成后将被重新包装,从而引入了多层可选包装的混乱可能性。

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

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

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


阅读 297

收藏
2020-07-07

共1个答案

一尘不染

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

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

一个。你可能会忘记,

b。导致代码非常难看。

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

现在,您的问题涉及仅在带有的块内存在的展开值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:在函数中先检查计数,然后再执行do
array.first!。但这!就像向您发出的信号–当心,您正在做一些危险的事情,如果您的代码不完全正确,您将感到遗憾。

可选选项还有助于使其他选项更美观。假设您要在数组为空的情况下默认该值。代替这个:

array.count > 0 ? a[0] : somedefault

你可以这样写:

array.first ?? somedefault

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

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

find当您了解可选用语时,通过返回可选内容是很自然的事情,因为这样做很明显是因为结果可能无效。上面提到的关于安全性的所有事情同样适用-
您不能无意间忘记并将结果用作索引,因为您必须先将其拆开。

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

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

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

2020-07-07