3

juste se demandant si cela est possible dans Swift 2.2, KVO sur une propriété calculée !?KVO sur les propriétés calculées de Swift

-à-dire:

var width = 0 
    var height = 0 

    private var area : Double { 
      get { 
       return with * height 
      } 
    } 

    self.addOberser(self, forKeyPath: "area", ...... 

Est-ce qu'un code client modifiant la hauteur avec ou observeValueForKeyPath déclencheur? Il suffit de vérifier avant de s'engager dans un refactor de classe maire. La syntaxe de KVO est aussi agaçante que ça ne vaut même pas un terrain de jeu si quelqu'un a une réponse sous la main (je suppose que la réponse est NON)

salutations! ~ d

+0

Le KVO est tout au sujet du compositeur, où est votre @dhomes setter? –

+1

Jetez un coup d'œil à ['RxSwift'] (https://github.com/ReactiveX/RxSwift). – dfri

+0

@Basheer_CAD c'est le point! je me réfère peut-on observer une propriété calculée en lecture seule? définirait la largeur ou la hauteur déclencher un nouveau calcul de surface? (Supposerait non, mais peut-être un compilateur de fantaisie ????) –

Répondre

9

Ce code ne fonctionnera pas pour deux raisons:

  1. Vous devez ajouter l'attribut dynamic à la propriété area, tel que décrit dans la section « Observation valeur-clé » sous “Adopting Cocoa Design Patterns” in Using Swift with Cocoa and Objective-C.

  2. Vous devez déclarer que area dépend de width et height comme décrit dans “Registering Dependent Keys” in the Key-Value Observing Programming Guide. (Cela s'applique à Objective-C et Swift.) Et pour que cela fonctionne, vous devez également ajouter dynamic à width et height.

    (Vous pourriez plutôt appeler willChangeValueForKey et didChangeValueForKey chaque fois que width ou height changements, mais il est généralement plus facile à mettre en œuvre tout keyPathsForValuesAffectingArea.)

Ainsi:

class MyObject: NSObject { 

    dynamic var width: Double = 0 
    dynamic var height: Double = 0 

    dynamic private var area: Double { 
     return width * height 
    } 

    class func keyPathsForValuesAffectingArea() -> Set<String> { 
     return [ "width", "height" ] 
    } 

    func register() { 
     self.addObserver(self, forKeyPath: "area", options: [ .Old, .New ], context: nil) 
    } 

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { 
     print("observed \(keyPath) \(change)") 
    } 

} 

let object = MyObject() 
object.register() 
object.width = 20 
object.height = 5 

Sortie:

observed Optional("area") Optional(["old": 0, "new": 0, "kind": 1]) 
observed Optional("area") Optional(["old": 0, "new": 100, "kind": 1]) 
+1

Je crois que selon ces mêmes liens de documentation, vous êtes censé spécifier le contexte, non? – MarqueIV

+1

Habituellement, c'est une bonne idée d'utiliser un 'context' pour plusieurs raisons, mais cette réponse ne concernait pas cette partie de KVO. De plus, si vous n'héritez que de 'NSObject', vous n'avez pas besoin d'utiliser' context' à moins que vous ne le vouliez, car 'NSObject' ne s'enregistre pas pour les notifications KVO, il n'y a donc aucune possibilité de conflit avec votre superclasse. –

+0

Bonne info! Merci d'avoir partagé! – MarqueIV

1

Comme @Rob a déclaré dans sa réponse, faire areadynamic à observer de c-objectif

Ajoutez maintenant willSet { } et didSet { } pour width et height propriétés,
intérieur willSet pour les deux propriétés ajouter cette self.willChangeValueForKey("area") et didSet ajouter self.didChangeValueForKey("area");

Maintenant, les observateurs de area seront informés à chaque changement de largeur ou de hauteur.

Remarque: ce code n'est pas testé, mais je pense qu'il devrait faire ce qui devrait