Swift: передать массив по ссылке?

Я хочу передать мой Swift Array account.chats в chatsViewController.chats по ссылке (так что, когда я добавляю чат к account.chats, chatsViewController.chats все еще указывает на account.chats). I.e., я не хочу, чтобы Swift разделял два массива, когда изменяется длина account.chats.

Ответ 1

Структуры в Swift передаются по значению, но вы можете использовать модификатор inout для изменения вашего массива (см. ответы ниже). Классы передаются по ссылке. Array и Dictionary в Swift реализованы как структуры.

Ответ 2

Для оператора параметров функции мы используем:

let (это оператор по умолчанию, поэтому мы можем опустить let), чтобы сделать параметр постоянным (это значит, что мы не можем модифицировать даже локальную копию).

var, чтобы сделать его переменной (мы можем изменить его локально, но это не повлияет на внешнюю переменную, которая была передана функции); и

inout, чтобы сделать его входным параметром. In-out означает передачу переменной по ссылке, а не по значению. И это требует не только принятия значения по ссылке, но и для передачи его по ссылке, поэтому передайте его с и - foo(&myVar) вместо foo(myVar)

Итак, сделайте так:

var arr = [1, 2, 3]

func addItem(inout localArr: [Int]) {
    localArr.append(4)
}

addItem(&arr)    
println(arr) // it will print [1, 2, 3, 4]

Чтобы быть точным, это не просто ссылка, а реальный псевдоним для внешней переменной, поэтому вы можете сделать такой трюк с любым типом переменной, например с целым числом (вы можете присвоить ему новое значение), хотя оно может не будет хорошей практикой, и может быть путаным изменять примитивные типы данных, подобные этому.

Ответ 3

Определите себя BoxedArray<T>, который реализует интерфейс Array, но делегирует все функции сохраненному свойству. Как таковой

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

  // ...

  subscript (index: Int) -> T { 
    get { return array[index] }
    set(newValue) { array[index] = newValue }
  }
}

Используйте BoxedArray везде, где вы используете Array. Назначение BoxedArray будет по ссылке, это класс, и, таким образом, изменения в хранимом свойстве через интерфейс Array будут видны всем ссылкам.

Ответ 4

Swift 3 Xcode 8

var arr = [1, 2, 3]

func addItem(_ localArr: inout [Int]) {
    localArr.append(4)
}

addItem(&arr)
print(arr)

Ответ 5

Что-то вроде

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

???

Ответ 6

Еще один вариант заключается в том, чтобы потребитель массива запрашивал у владельца при необходимости. Например, что-то вроде:

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. Обратите внимание, что это не поможет вам, если вы хотите также изменить массив из класса контроллера представления.

Ответ 7

Swift 3 и Xcode 8:

var myArray = [1, 2, 3]

for (index, value) in myArray.enumerated()  {
    // if you don't need the value you could do: for (index, _) in myArray.enumerated()
    myArray[index].append(4)
}