Arrays Swift:通过引用传递数组?

Arrays Swift:通过引用传递数组?,arrays,swift,pass-by-reference,Arrays,Swift,Pass By Reference,我想通过引用将我的Swift数组帐户.chats传递给chatsViewController.chats(这样,当我向帐户.chats添加聊天时,chatsViewController.chats仍然指向帐户.chats)。也就是说,当account.chats的长度发生变化时,我不希望Swift将这两个数组分开 var a : Int[] = [] func test(inout b : Int[]) { b += [1,2,3,4,5] } test(&a) println(

我想通过引用将我的Swift
数组
帐户.chats
传递给
chatsViewController.chats
(这样,当我向
帐户.chats添加聊天时,
chatsViewController.chats
仍然指向
帐户.chats
)。也就是说,当
account.chats
的长度发生变化时,我不希望Swift将这两个数组分开

var a : Int[] = []
func test(inout b : Int[]) {
    b += [1,2,3,4,5]
}
test(&a)
println(a)

??

Swift中的结构按值传递,但您可以使用
inout
修饰符修改数组(请参见下面的答案)。类是通过引用传递的数组
和字典被实现为结构

定义一个
BoxedArray
,它实现
数组
接口,但将所有函数委托给存储的属性。因此

class BoxedArray<T> : MutableCollection, Reflectable, ... {
  var array : Array<T>

  // ...

  subscript (index: Int) -> T { 
    get { return array[index] }
    set(newValue) { array[index] = newValue }
  }
}
class-BoxedArray:MutableCollection,可反射。。。{
变量数组:数组
// ...
下标(索引:Int)->T{
获取{返回数组[索引]}
集合(newValue){array[index]=newValue}
}
}

使用
BoxedArray
可以使用
数组的任何位置。
BoxedArray
的赋值将通过引用进行,它是一个类,因此通过
Array
接口对存储属性的更改将对所有引用可见

对于我们使用的函数参数运算符:

let
(它是默认运算符,因此我们可以省略let)以使参数为常量(这意味着我们甚至不能修改本地副本)

var
使其变为变量(我们可以在本地修改它,但它不会影响传递给函数的外部变量);和

inout
使其成为输入输出参数。In-out实际上是指通过引用而不是通过值传递变量。它不仅需要通过引用来接受值,还需要通过引用来传递值,因此使用
&
-
foo(&myVar)
传递值,而不仅仅是
foo(myVar)

这样做:

var-arr=[1,2,3]
func addItem(localArr:inout[Int]){
localArr.append(4)
}
附加项(&arr)
print(arr)//它将打印[1,2,3,4]


确切地说,它不仅是一个引用,而且是外部变量的真实别名,因此您可以对任何变量类型执行此操作,例如整数(您可以为其指定新值),尽管这样修改基本数据类型可能不是一种好的做法,而且可能会造成混乱。

另一种选择是让数组的使用者根据需要向所有者索要。例如,以下内容:

class Account {
    var chats : [String]!
    var chatsViewController : ChatsViewController!

    func InitViewController() {
        chatsViewController.getChats = { return self.chats }
    }

}

class ChatsViewController {
    var getChats: (() -> ([String]))!

    func doSomethingWithChats() {
        let chats = getChats()
        // use it as needed
    }
}
然后,您可以在Account类中任意修改数组。请注意,如果您还想从视图控制器类修改阵列,这对您没有帮助。

对于Swift版本3-4(XCode 8-9),请使用


使用
inout
是一种解决方案,但由于数组是值类型,所以对我来说不是很快。就风格而言,我个人更喜欢返回一份经过变异的副本:

func doSomething(to arr: [Int]) -> [Int] {
    var arr = arr
    arr.append(3) // or likely some more complex operation
    return arr
}

var ids = [1, 2]
ids = doSomething(to: ids)
print(ids) // [1,2,3]

使用
NSMutableArray
NSArray
,它们是类

这样,您不需要实现任何包装器,并且可以使用内置桥接

open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration


我想问题是要找到一种方法,让两个不同对象的属性指向同一个数组。如果是这种情况,Kaan的答案是正确的:必须将数组包装在类中,或者使用NSArray。对,inout仅在函数体的生命周期内有效(无闭包行为)次要nit:it's
func test(b:inout[Int])
。。。也许这是一个古老的语法;我在2016年才进入Swift,这个答案是从2014年开始的,所以可能过去情况有所不同?数组在Swift中不是按值复制/传递的-它在Swift中的行为与常规结构非常不同。请看@Boon数组在语义上仍然是按值复制/传递的,但只是为了使用而进行了优化。我不建议使用
NSArray
,因为
NSArray
和Swift数组有细微的语义差异(例如引用类型),这可能会导致更多的错误。这让我非常痛苦。我一直在绞尽脑汁为什么事情不能正常工作。如果将
inout
与结构一起使用会怎么样?这并不能真正解释如何将数组用作引用而不是复制的实例变量。我认为inout使用getter和setter将数组复制到一个临时数组,然后在退出函数时重置它-即它实际复制“输入输出”使用“输入复制输出”或“按值调用”结果。但是,作为一种优化,可以参考使用。“作为一种优化,当参数是存储在内存中物理地址的值时,函数体内外都使用相同的内存位置。这种优化行为称为引用调用;它在消除复制开销的同时满足复制入复制出模型的所有要求。”在Swift 3中,
inout
位置已更改,即
func addItem(localArr:inout[Int])
此外,
var
不再适用于函数参数属性。有点可怕的解决方案:)-不太优雅-但它似乎可以工作。好吧,这肯定比退回到“使用NSArray”获得“按引用传递语义”要好!我只是觉得把数组定义为struct而不是class是语言设计的错误,我同意。还有一个令人憎恶的地方是
String
Any
的子类型,但是如果你
import Foundation
,那么
String
就变成了
AnyObject
的子类型。我最后只是把
account
作为一个全局变量,并将
ChatsViewController
chats
属性定义为:
var chats:[Chat]{return account.chats}
。这类事情会降低性能。它使用了稍微少一点的手机电池来修改原始阵列:)I resp
open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration