web-dev-qa-db-fra.com

Swift: Passer tableau par référence?

Je veux passer mon Swift Arrayaccount.chats à chatsViewController.chats par référence (afin que, lorsque j'ajoute une discussion à account.chats, chatsViewController.chats pointe toujours sur account.chats). C'est-à-dire que je ne veux pas que Swift sépare les deux tableaux lorsque la longueur de account.chats change.

115
ma11hew28

Les structures dans Swift sont passées par valeur, mais vous pouvez utiliser le modificateur inout pour modifier votre tableau (voir les réponses ci-dessous). Les classes sont passées par référence. Array et Dictionary dans Swift sont implémentés en tant que structures.

62
Kaan Dedeoglu

Pour l'opérateur de paramètre de fonction, nous utilisons:

let (opérateur par défaut, nous pouvons donc omettre let) pour rendre un paramètre constant (cela signifie que nous ne pouvons pas modifier même la copie locale);

var pour le rendre variable (nous pouvons le modifier localement, mais cela n'affectera pas la variable externe qui a été transmise à la fonction); et

inout pour en faire un paramètre in-out. In-out signifie en fait passer variable par référence, pas par valeur. Et cela nécessite non seulement d’accepter valeur par référence, mais aussi de le transmettre par référence; transmettez-le donc avec & - foo(&myVar) au lieu de simplement foo(myVar)

Alors faites-le comme ça:

var arr = [1, 2, 3]

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

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

Pour être exact, il ne s’agit pas simplement d’une référence, mais d’un véritable alias pour la variable externe. Vous pouvez donc réaliser cette astuce avec n’importe quel type de variable, par exemple un entier (vous pouvez lui affecter une nouvelle valeur), bien que ce ne soit pas nécessairement un type de variable. bonne pratique et il peut être déroutant de modifier les types de données primitifs comme celui-ci.

132
Gene Karasev

Définissez vous-même un BoxedArray<T> qui implémente l'interface Array mais délègue toutes les fonctions à une propriété stockée. En tant que tel

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

  // ...

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

Utilisez le BoxedArray partout où vous utiliseriez un Array. L'affectation d'une BoxedArray se fera par référence. Il s'agit d'une classe. Les modifications apportées à la propriété stockée via l'interface Array seront donc visibles pour toutes les références.

21
GoZoner

Pour Swift versions 3-4 (XCode 8-9), utilisez

var arr = [1, 2, 3]

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

addItem(&arr)
print(arr)
17
user6798251

Quelque chose comme

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

???

3
Christian Dietrich

Une autre option consiste à faire en sorte que le consommateur du tableau le demande au propriétaire. Par exemple, quelque chose comme:

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
    }
}

Vous pouvez ensuite modifier le tableau autant que vous le souhaitez dans la classe Account. Notez que cela ne vous aide pas si vous souhaitez également modifier le tableau à partir de la classe du contrôleur de vue.

2
elRobbo

Utiliser inout est une solution, mais cela ne me semble pas très rapide, car les tableaux sont des types valeur. Stylistiquement, je préfère personnellement renvoyer une copie mutée:

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]
0
ToddH

utiliser un NSMutableArray ou un NSArray, qui sont des classes

de cette façon, vous n'avez pas besoin d'implémenter d'encapsuleur et pouvez utiliser la génération de pontage

open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration
0
Peter Lapisu