Swift中的可选数组与空数组

时间:2014-11-07 23:30:00

标签: arrays swift optional

我在Swift中有一个简单的Person类,看起来像这样:

class Person {
    var name = "John Doe"
    var age = 18
    var children = [Person]?

    \\ init function goes here, but does not initialize children array
}

我可以简单地声明它并将其初始化为一个空数组,而不是声明children是一个可选数组:

var children = [Person]()

我正在尝试确定哪种方法更好。将数组声明为可选数组意味着它根本不会占用任何内存,而空数组至少为它分配了一些内存,对吗?因此,使用可选数组意味着至少会节省一些内存。我想我的第一个问题是:这里是否真的存在实际的内存节省,或者我对此的假设不正确?

另一方面,如果它是可选的,那么每次我尝试使用它时,我都必须在添加或删除对象之前检查它是否为nil。因此,那里会有一些效率损失(但我想的并不多)。

我有点像可选方法。不是每个Person都会生育孩子,那么为什么children nil决定安顿下来并养育一个家庭,为什么不让Person成为{{1}}?

无论如何,我想知道一种方法或另一种方法是否存在任何其他特定优点或缺点。这是一个反复出现的设计问题。

6 个答案:

答案 0 :(得分:19)

我要从Yordi做出相反的情况 - 一个空阵列就像清楚地说'#34;这个人没有孩子",并且会为你节省大量的麻烦。 children.isEmpty可以轻松检查孩子的存在情况,而且您不必解开或担心意外的nil

另外,作为一个注释,将某些内容声明为可选内容并不意味着它占用零空间 - 它是.None的{​​{1}}个案例。

答案 1 :(得分:15)

在空数组或可选项之间进行选择的能力使我们能够应用从语义角度更好地描述数据的能力。

我会选择:

  • 如果列表可以为空,则为空数组,但它是瞬态状态,最后应至少有一个元素。非选择性表明数组不应为空
  • 如果列表在容器实体的整个生命周期中可能为空,则为可选项。作为一个可选项表明数组可以是空的

让我举一些例子:

  • 包含主数据和详细信息的采购订单(每个产品一个详细信息):采购订单可以有0个详细信息,但这是暂时状态,因为购买订单包含0个产品没有意义
  • 有孩子的人:一个人一辈子都没有孩子。它不是一种短暂的状态(虽然也不是永久性的),但使用一个可选的,很明显,一个人没有孩子是合法的。

请注意,我的观点仅仅是为了使代码更清晰和自我解释 - 我认为在选择一个选项或另一个选项时,在性能,内存使用等方面没有任何显着差异。

答案 2 :(得分:12)

有趣的是,我们最近几乎没有就这个同样的问题进行讨论。

有人认为存在微妙的语义差异。例如。 nil表示一个人没有任何孩子,但0是什么意思?这是否意味着“有孩子,他们整个0”?就像我说的那样,纯语义“有0个孩子”“没有孩子”在代码中使用这个模型没有任何区别。在那种情况下,为什么不选择更直接和更少的守护 - ? - y方法?

有人建议保留一个nil可能表明,例如,当从后端获取模型出错时我们得到错误而不是孩子。但我认为模型不应该尝试使用这种类型的语义,并且nil不应该用作过去某些错误的指示。

我个人认为该模型应该尽可能愚蠢,在这种情况下 dumbest 选项是空数组。

拥有可选内容会让您将?拖到天数结束时反复使用guard letif let??

您需要为NSCoding实施提供额外的解包逻辑,当您在任何视图控制器中显示该模型时,您必须执行person.children?.count ?? 0而不是直截了当person.children.count

所有操作的最终目标是在UI上显示内容。 你真的会说

吗?

“这个人没有孩子”和“这个人有0个孩子”nil和空数组相应吗?我希望你不会:)。

Last Straw

最后,这真是我最强的论据

在Cocoa框架中有很多这样的例子:UIViewController::childViewControllers等等。

即使是纯粹的Swift世界:Dictionary::keys虽然这可能有点牵强。

为什么人有children个孩子,但SKNode没有?对我来说,这个比喻是完美的。嘿,即使nil的方法名称是SKNode:)

我的观点:必须有一个明显的理由将这些数组保持为可选项,就像一个非常好的数组,否则空数组提供相同的语义而不需要解包。

The Last Last Straw

最后,一些非常好的文章的引用,每一篇

在娜塔莎的帖子中,你会发现link to NSHipster's blog post Swiftification 段落,你可以读到这个:

  

例如,不是将NSArray返回值标记为可为空,而是修改了许多API以返回空数组 - 语义上这些数组具有相同的值(即,没有任何内容),但非可选数组更易于使用

答案 3 :(得分:5)

有时,不存在的东西和空的东西之间存在差异。

假设我们有一个应用程序,用户可以修改已解析的电话号码列表,我们保存所述修改。如果没有发生任何修改,则数组应为零。如果用户通过删除它们来修改已解析的数字,则所有数组都应为空。

当我们无法区分属性为空或不存在空时是要走的路。如果Person失去了他们唯一的孩子,我们应该只需删除那个孩子并拥有一个空数组而不必检查count是否为1然后将整个数组设置为{{1} }。

答案 4 :(得分:2)

我总是使用空数组。

在我的拙见中,Swift中选项的最重要目的是安全地包装一些可能为零的值。一个数组已经充当了这种类型的包装器 - 你可以询问数组是否有任何内部&使用for循环,映射等安全地访问它的值。我们需要在包装器中放置一个包装器吗?我不这么认为。

答案 5 :(得分:1)

Swift旨在利用可选值和可选的展开功能。

也可以将数组声明为nil,因为它可以为您节省非常小的(几乎没有显着的)内存量。

我会使用可选数组而不是代表nil值的数组来保持Swift的设计模式满意:)

我也认为

if let children = children {

}

看起来比:

更好
if(children != nil){

}