在Swift中在视图控制器之间传递数组/对象

6

继续这个问题:为什么Swift数组赋值不一致(既不是引用也不是深复制)? -

我一直在尝试在Swift中传递对象并注意到一些奇怪的结果。

为了澄清我之前(在Swift之前)所熟悉的行为,举个例子,在我的一个应用程序中(用Obj C编写),我有一个“通知列表”的概念。 - 实际上只是自定义对象的数组。

在该应用程序中,我经常将全局“通知”数组传递给各种视图控制器,这些视图控制器提供UI以更新列表。

当我将全局数组传递给子视图控制器时,我将其分配给接收对象中的本地数组变量。然后,通过更新/更改本地数组,这些更改会反映在根视图控制器上的全局数组中。我理解这种行为在Objective C中是隐含的,因为对象是按引用传递的,但这真的很方便,我一直在尝试在Swift中复制这种行为。

然而,当我在Swift中重写我的应用程序时,我遇到了问题。

我首先尝试从rootViewController传递一个Swift字符串数组(而不是NSMutableArray)到子视图控制器(如上所述)。

当将字符串数组传递给子视图控制器时,其行为如下:

我传入:

[Bill,Bob,Jack] 然后将此传递的数组分配给本地数组以进行本地修改,

然后我将字符串“Frank”附加到本地数组

结果是:

本地数组 = [Bill,Bob,Jack,Frank]

全局数组 = [Bill,Bob,Jack]

没有将本地数组的任何更改反映回全局数组。 - 如果更改元素(而不更改数组的长度),则会发生相同的结果。

我还尝试了上述实验的更现实世界的例子 - 将我的自定义“通知”对象数组传递给子视图控制器。 对于分配给本地对象数组的所有自定义对象的更改都不会反映在原始全局数组中。

这种行为对我来说并不理想,我认为最佳做法是使用委托协议将修改后的数组(或任何对象)传递回父对象,然后手动更新全局数组? - 如果是这样,那么相对于Objective C风格的行为,这将创建相当多的额外工作。

最后我确实尝试了inout关键字,这使你能够直接修改传递给目标对象的函数参数变量。
更改将反映回全局数组(或对象),但问题在于,如果输入参数被分配给本地变量(以在init函数范围外进行编辑),则对本地变量的更改仍未反映在全局范围内。
希望上述内容有意义 - 它真的让我在Swift中的生产力受到限制。
我是否遗漏了什么,还是说这种矛盾的行为是可以预期的?
如果是这样,那么传递修改后的数据的最佳做法是什么,使用委托?

1
你怎么可能投票关闭问题 - 你显然甚至没有读我的问题。- 我在我的问题开头引用了那个问题。这是完全不同的问题。 - Woodstock
1
你问了一个好问题!忽略那些没有理由给别人的问题点踩甚至关闭问题的白痴。 - Bagusflyer
2个回答

3
链接提供了答案 - 因为性能。尽管这种行为可能不适合您,但我认为依赖于调用方法来修改参数的副作用是不被认为是理想的行为 - 特别是在多线程、多核环境中,数据结构可能会被破坏。在我看来,依赖副作用的设计是有缺陷的。
如果函数需要修改“全局”变量,则应返回新值;如果不可能,则应在对象内部包装数组,并提供适当的函数来操作数据值。Swift 在数组方面模糊了内在和对象之间的界限,这使得它有点令人困惑 - 在 Objective-C 中,NSMutableArray 是一个对象,因此始终通过引用传递。
要通知其他对象数据已更改,可以使用观察者模式。典型的代理模式只有一个注册的委托 - 使用观察者模式,您可以有多个注册的观察者。您可以通过 NSNotificationCenter 或“委托”数组来实现这一点。前者具有比委托更高的解耦优势。

这对我来说似乎很疯狂,传递对象并维护“本地”和“全局”对象的状态和同步是一种负担。随着应用程序的增长,这非常限制。您建议包装数组听起来不错,直到使用包装对象的数组遇到相同的问题.....在上面的Viewcontroller示例中,您认为使用委托在每次更改时传递数据是最佳实践吗?-他们为什么要费心使用inout之类的东西? - Woodstock
我认为将数组封装在对象中是最佳实践。在面向对象编程中,只有在满足需求的情况下才使用内置类型 - Swift 数组无法满足您的需求,因此创建一个可以满足需求的对象。这也可以说是更好的风格,并且使您可以自由选择不同的内部数据结构(如果需要的话)。您还可以使用 NSMutableArray 而不是 Swift 数组。 - Paulw11
有趣,感谢反馈。您不认为不知道何时通过引用传递对象以及何时不传递对象是有限制的吗?您认为委托协议是否也可以正确地在对象之间传递数据? - Woodstock
哦,好的——所以如果我理解你的意思正确的话——委托协议是将数据传递回单个相关对象的好方法,而像通知中心这样的东西则适用于多个对象...如果我用一个对象包装我的数组(或者使用NSMutableArray),我会得到ObjC风格吗?那么在Swift中,所有真正的对象(类对象)都是通过引用传递并且像ObjC示例一样行为吗? - Woodstock
在我的情况下,我将数组封装在一个对象中,并通过另一个对象的属性传递它。但是当我尝试修改数组元素时,我收到了一个错误信息:“'@lvalue $T8'与'Int'不相同”,这对我来说毫无意义。 - Bagusflyer
显示剩余4条评论

1
为什么不创建一个包含数组变量的模型类。向模型类中添加方法来操作数组并将新实例存储在属性中。在启动时创建模型类的单个实例并将其传递给视图控制器。它们都通过模型或模型类中的方法访问数组。Swift 的行为(在大小更改时复制数组)将对所有视图控制器隐藏。

不错的建议,谢谢 - 我也想到了,但与仅通过引用传递相比,这会带来很多麻烦。 - Woodstock
这实际上就是我所做的。但是我得到了编译错误。如果我修改数组元素的值,我会得到“@lvalue $T8”与“Int”不相同的错误。如果我在Model类中调用方法。我得到“Immutable value of type 'MyObject' only has mutating members named 'myMethod'”错误。我真的不明白。我的方法是mutating,我的模型被声明为var,应该是mutating的。 - Bagusflyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接