2017-06-28 2 views
0

J'ai deux classes. Classe A a la classe B, mais la classe B ne connaît pas l'existence de la classe AKVO infinit loop avec liaison bidirectionnelle

Les deux classes peuvent être modifiés par des facteurs externes (tels que les services ou la logique)

Mais je dois garder les deux classes synchronisées avec la même valeur

Comme classe A connaît la classe B, je peux faire une affectation directe après sa valeur est modifiée

Pour la classe B connaître la classe A, j'ai décidé de mettre en œuvre KVO, de cette façon la classe A est averti lorsque la classe B change

Mon code ressemble à ceci

class A : NSObject { 
    var b : B 

    @objc dynamic var anOtherString:String? { 
     didSet{ 
      b.someString = self.anOtherString 
     } 
    } 

    override init() { 
     self.b = B() 
     super.init() 
     addObserver(self, forKeyPath: #keyPath(b.someString), options: [.old , .new], context: nil) 
    } 

    // MARK: - Key-Value Observing 
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 

     if keyPath == #keyPath(b.someString) { 
      // Update Time Label 
      anOtherString = b.someString 
     } 
    } 

} 


class B : NSObject { 
    @objc dynamic var someString: String? 
} 

Le problème est que mon code reste en boucle infinie

Parce que chaque fois que ma classe B est modifiée, elle notifie la classe A, et quand la classe A est mise à jour, elle change à nouveau la valeur de la classe B qui crée une nouvelle notification et ainsi de suite ...

J'ai déjà essayé d'analyser le Thread.callStackSymbols pour détecter le cycle et l'arrêter mais sans succès.

+0

Est-ce que votre code réel faire plus? Pour le code que vous avez posté, il n'y a pas de raison pour que la classe A observe la classe B. Tout ce que vous faites dans la classe A quand 'b.someString' est changé, c'est mettre à jour' b.someString' avec la même valeur. Il n'y a aucune raison pour ça. – rmaddy

+0

Bien sûr, vous pouvez ajouter une vérification si l'ancienne et la nouvelle valeur sont les mêmes. Si elles sont identiques, ne faites rien. – rmaddy

+0

@maddy - J'ai pensé à vérifier les anciennes et les nouvelles valeurs. Mais ceci est dans une application très complexe et dans des cas spécifiques ne fonctionne pas, et il est nécessaire de créer des solutions alternatives pour ces cas – Pedro

Répondre

0

Puisque vous ne pouvez pas permettre A à B mettre à jour lorsque A a été changé en raison de B, vous pourriez avoir une variable booléenne qui suit si A doit mettre à jour B.

class A : NSObject { 
    var b : B 
    var bChanged: Bool = false // Logic to track if B made a change 

    @objc dynamic var anOtherString:String? { 
     didSet{ 
      // If B did not make a change, then update B 
      if !bChanged { 
       b.someString = self.anOtherString 

      // Otherwise set the flag 
      }else { 
       bChanged = false 
      } 
     } 
    } 

    override init() { 
     self.b = B() 
     super.init() 
     addObserver(self, forKeyPath: #keyPath(b.someString), options: [.old , .new], context: nil) 
    } 

    // MARK: - Key-Value Observing 
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 

     if keyPath == #keyPath(b.someString) { 
      // Update Time Label 
      bChanged = true // B made a change 
      anOtherString = b.someString 
     } 
    } 
}