177 votes

L'observation clé-valeur (KVO) est-elle disponible dans Swift ?

Dans l'affirmative, existe-t-il des différences essentielles qui n'étaient pas présentes lors de l'utilisation de l'observation clé-valeur en Objective-C ?

2 votes

Un projet d'exemple qui démontre l'utilisation de KVO dans une interface UIKit via Swift : github.com/jameswomack/kvo-in-swift

0 votes

@JanDvorak Voir le Guide de programmation de KVO qui constitue une bonne introduction au sujet.

1 votes

Bien que cela ne réponde pas à votre question, vous pouvez également lancer des actions en utilisant la fonction didset().

158voto

Rob Points 70987

Vous pouvez utiliser KVO en Swift, mais seulement pour dynamic les propriétés de NSObject sous-classe. Considérons que vous vouliez observer le bar d'un Foo la classe. Dans Swift 4, spécifiez bar como dynamic dans votre NSObject sous-classe :

class Foo: NSObject {
    @objc dynamic var bar = 0
}

Vous pouvez alors vous inscrire pour observer les changements apportés au bar propriété. Dans Swift 4 et Swift 3.2, cela a été grandement simplifié, comme indiqué dans Utilisation de l'observation clé-valeur en Swift :

class MyObject {
    private var token: NSKeyValueObservation

    var objectToObserve = Foo()

    init() {
        token = objectToObserve.observe(\.bar) { [weak self] object, change in  // the `[weak self]` is to avoid strong reference cycle; obviously, if you don't reference `self` in the closure, then `[weak self]` is not needed
            print("bar property is now \(object.bar)")
        }
    }
}

Notez que, dans Swift 4, nous disposons désormais d'une saisie forte des chemins de clés à l'aide du caractère backslash (la balise \.bar est le chemin d'accès au bar propriété de l'objet observé). De plus, parce qu'il utilise le modèle de fermeture de complétion, nous n'avons pas besoin de supprimer manuellement les observateurs (lorsque la fonction token sort du champ d'application, l'observateur est supprimé pour nous) et nous n'avons pas non plus à nous soucier de l'appel de la fonction super si la clé ne correspond pas. La fermeture est appelée uniquement lorsque cet observateur particulier est invoqué. Pour plus d'informations, voir la vidéo de la WWDC 2017, Quoi de neuf dans la Fondation .

Dans Swift 3, pour observer cela, c'est un peu plus compliqué, mais très similaire à ce que l'on fait en Objective-C. A savoir, vous implémentez observeValue(forKeyPath keyPath:, of object:, change:, context:) ce qui permet (a) de s'assurer que nous traitons avec notre contexte (et non avec quelque chose que notre super s'est inscrite pour l'observer) ; et ensuite (b) soit la traiter, soit la transmettre à l'instance de l super la mise en œuvre, si nécessaire. Et assurez-vous de vous retirer en tant qu'observateur lorsque cela est approprié. Par exemple, vous pouvez retirer l'observateur lorsqu'il est désalloué :

Dans Swift 3 :

class MyObject: NSObject {
    private var observerContext = 0

    var objectToObserve = Foo()

    override init() {
        super.init()

        objectToObserve.addObserver(self, forKeyPath: #keyPath(Foo.bar), options: [.new, .old], context: &observerContext)
    }

    deinit {
        objectToObserve.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard context == &observerContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }

        // do something upon notification of the observed object

        print("\(keyPath): \(change?[.newKey])")
    }

}

Attention, vous ne pouvez observer que les propriétés qui peuvent être représentées en Objective-C. Ainsi, vous ne pouvez pas observer les génériques, Swift struct types, Swift enum types, etc.

Pour une discussion sur l'implémentation de Swift 2, voir ma réponse originale, ci-dessous.


Utilisation de la dynamic mot-clé pour atteindre la KVO avec NSObject est décrite dans le document Observation de la valeur d'une clé de la section Adopter les conventions de conception Cocoa chapitre du Utiliser Swift avec Cocoa et Objective-C guide :

L'observation clé-valeur est un mécanisme qui permet aux objets d'être informés des changements apportés à des propriétés spécifiques d'autres objets. Vous pouvez utiliser l'observation clé-valeur avec une classe Swift, à condition que celle-ci hérite de la classe NSObject classe. Vous pouvez utiliser ces trois étapes pour mettre en œuvre l'observation clé-valeur en Swift.

  1. Ajouter le dynamic à toute propriété que vous souhaitez observer. Pour plus d'informations sur les dynamic voir Nécessité d'un dispatching dynamique .

    class MyObjectToObserve: NSObject {
        dynamic var myDate = NSDate()
        func updateDate() {
            myDate = NSDate()
        }
    }
  2. Créer une variable contextuelle globale.

    private var myContext = 0
  3. Ajoutez un observateur pour le chemin de la clé, et remplacez la fonction observeValueForKeyPath:ofObject:change:context: et supprimer l'observateur dans la méthode deinit .

    class MyObserver: NSObject {
        var objectToObserve = MyObjectToObserve()
        override init() {
            super.init()
            objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext)
        }
    
        override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
            if context == &myContext {
                if let newValue = change?[NSKeyValueChangeNewKey] {
                    print("Date changed: \(newValue)")
                }
            } else {
                super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
            }
        }
    
        deinit {
            objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
        }
    }

[Note : cette discussion sur KVO a été retirée de la page d'accueil du site Web de la Commission européenne. Utiliser Swift avec Cocoa et Objective-C qui a été adapté pour Swift 3, mais qui fonctionne toujours comme indiqué en haut de cette réponse].


Il est intéressant de noter que Swift possède son propre système natif observateur immobilier mais c'est pour une classe qui spécifie son propre code qui sera exécuté lors de l'observation de ses propres propriétés. La KVO, en revanche, est conçue pour s'enregistrer afin d'observer les modifications apportées à une propriété dynamique d'une autre classe.

0 votes

Quel est le but de myContext et comment observer des propriétés multiples ?

1 votes

Selon Guide de programmation de KVO : " Lorsque vous enregistrez un objet en tant qu'observateur, vous pouvez également fournir un context pointeur. Le site context Le pointeur est fourni à l'observateur lorsque observeValueForKeyPath:ofObject:change:context: est invoquée. Le site context Le pointeur peut être un pointeur C ou une référence d'objet. Le site context Le pointeur peut être utilisé comme un identifiant unique pour déterminer le changement observé ou pour fournir d'autres données à l'observateur."

0 votes

Vous devez supprimer l'observateur dans deinit

107voto

Catfish_Man Points 15439

(Modifié pour ajouter de nouvelles informations) : voyez si l'utilisation du cadre Combine peut vous aider à accomplir ce que vous voulez, plutôt que d'utiliser KVO.

Oui et non. La KVO fonctionne sur les sous-classes de NSObject comme elle l'a toujours fait. Il ne fonctionne pas pour les classes qui ne sous-classent pas NSObject. Swift ne dispose pas (du moins actuellement) de son propre système d'observation natif.

(Voir les commentaires pour savoir comment exposer d'autres propriétés en tant que ObjC afin que le KVO puisse travailler dessus).

Voir le Documentation Apple pour un exemple complet.

0 votes

Pour info, j'ai rempli un rapport de bogue avec Apple à ce sujet. J'encourage tous les autres qui aimeraient voir un système d'observation KVO ou similaire dans swift, à faire de même.

75 votes

Depuis Xcode 6 beta 5, vous pouvez utiliser la fonction dynamic sur toute classe Swift pour activer le support KVO.

7 votes

Hourra pour @fabb ! Pour plus de clarté, le dynamic Le mot clé va sur la propriété que vous voulez rendre observable par une valeur clé.

92voto

slazyk Points 639

A la fois oui et non :

  • En effet, vous pouvez utiliser les mêmes vieilles API KVO en Swift pour observer les objets Objective-C.
    Vous pouvez également observer dynamic des propriétés des objets Swift héritant de NSObject .
    Mais... Non il n'est pas fortement typé comme on pourrait s'attendre à ce que le système d'observation natif de Swift le soit.
    Utiliser Swift avec Cocoa et Objective-C | Observation des valeurs clés

  • Non Pour l'instant, il n'existe pas de système intégré d'observation des valeurs pour les objets arbitraires de Swift.

  • il existe des modules intégrés Observateurs de la propriété qui sont fortement typés.
    Mais... Non ils ne sont pas KVO, puisqu'ils ne permettent que l'observation des propriétés propres des objets, ne supportent pas les observations imbriquées ("key paths"), et vous devez les implémenter explicitement.
    Le langage de programmation Swift - Observateurs de propriétés

  • Dans le cas de l'observation des valeurs, vous pouvez mettre en œuvre une observation explicite des valeurs, qui sera fortement typée et permettra d'ajouter des gestionnaires multiples à partir d'autres objets, et même de prendre en charge l'imbrication et les "chemins de clés".
    Mais... Non ce ne sera pas la KVO puisqu'elle ne fonctionnera que pour les propriétés que vous implémentez comme observables.
    Vous trouverez ici une bibliothèque permettant de mettre en œuvre ce type d'observation des valeurs :
    Observable-Swift - KVO pour Swift - Observation des valeurs et événements

9voto

Bryan Luby Points 1186

Oui.

KVO nécessite une répartition dynamique, il suffit donc d'ajouter l'option dynamic à une méthode, une propriété, un indice ou un initialisateur :

dynamic var foo = 0

El dynamic garantit que les références à la déclaration seront distribuées de manière dynamique et accessibles par le biais de l'option objc_msgSend .

4voto

ColinE Points 36907

Actuellement, Swift ne prend pas en charge de mécanisme intégré permettant d'observer les changements de propriété d'objets autres que le "soi", donc non, il ne prend pas en charge la KVO.

Cependant, KVO est un élément tellement fondamental d'Objective-C et de Cocoa qu'il semble tout à fait probable qu'il sera ajouté à l'avenir. La documentation actuelle semble le laisser entendre :

Observation de la valeur d'une clé

Informations à venir.

Utiliser Swift avec Cocoa et Objective-C

2 votes

Évidemment, le guide auquel vous faites référence décrit maintenant comment faire du KVO en Swift.

4 votes

Yep, maintenant mis en œuvre à partir de septembre 2014.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X