42 votes

KVO vs NSNotification vs protocole/délégués ?

J'ai une idée de ce qu'il faut utiliser et quand, mais l'usage exact n'est toujours pas clair pour moi. Quelqu'un peut-il m'expliquer avec un exemple ?

44voto

deanWombourne Points 26066

Utilisez un délégué si vous voulez parler à un seul objet. Par exemple, un tableView a un délégué - un seul objet doit être chargé de s'en occuper.

Utilisez les notifications si vous souhaitez informer tout le monde que quelque chose s'est produit. Par exemple, dans les situations de mémoire faible, une notification est envoyée pour indiquer à votre application qu'il y a eu une alerte mémoire. Comme de nombreux objets de votre application pourraient vouloir réduire leur utilisation de la mémoire, il s'agit d'une notification.

Je ne pense pas du tout que KVO soit une bonne idée et j'essaie de ne pas l'utiliser mais, si vous voulez savoir si une propriété a changé, vous pouvez écouter les changements.

J'espère que cela vous aidera.

PS Cela résume la raison pour laquelle je pense que KVO est cassé.

15voto

jbat100 Points 11445

Utilisez un délégué lorsqu'il existe une relation "maître/esclave" (le délégué connaît la classe et la classe connaît le délégué), avec une classe située plus haut dans la hiérarchie des contrôles, et lorsqu'il est clair qu'il n'y aura pas de situations où d'autres éléments (principalement l'interface utilisateur) seront intéressés par ce que la classe a à dire.

Utilisez les notifications lorsque la classe n'est pas intéressée à savoir qui écoute et combien ils sont, n'importe qui et n'importe quel nombre peut s'inscrire pour les notifications.

La KVO est utile pour écouter "à l'insu de la classe", bien que ce ne soit évidemment pas le cas, la classe sur laquelle la KVO est appliquée ne doit pas être modifiée.

2voto

user523234 Points 6873

Même si les trois peuvent répondre à vos besoins dans une situation donnée, déléguer reste une option préférable :

  1. Réutilisabilité.
  2. Auto-documenté. En examinant le fichier d'en-tête de la classe, on reconnaîtrait immédiatement ce que / comment l'échange de données a lieu.

2voto

NSResponder Points 14459

La délégation est un modèle de conception que vous utilisez lorsque vous voulez qu'un autre objet modifie le comportement de l'expéditeur. Exemple : les fenêtres de terminal évitent d'afficher les lignes ou les caractères qui sont coupés par les bords de la fenêtre, car le délégué de la fenêtre de terminal modifie la taille de la fenêtre pour s'en assurer.

La notification est un modèle à utiliser lorsque vous n'avez pas besoin de réponse. Exemple : vous recevez une notification indiquant que le système est sur le point de se mettre en veille. L'expéditeur de cette notification ne se soucie pas de ce que vous faites à ce sujet.

2voto

yoAlex5 Points 2350

Modèle de délégué, NotificationCenter, KVO

Délégué

delegate est un modèle de conception qui peut être lié au modèle structurel (modèle Decorator ou Wrapper de GoF) qui ajoute des comportements et des responsabilités à un objet sans modifier son code. Vous pouvez déplacer une certaine logique dans une autre classe d'aide ou l'utiliser comme un squelette. C'est une alternative à l'héritage. Techniquement, il utilise association [À propos] . Le langage Kotlin prend en charge delegate sur la couche de langage. Quant à iOS, il est généralement utilisé pour Loose coupling pour communiquer entre les classes Class1 <-> Class2 sans Retain cycle [À propos] donde SomeClass1 -> SomeClass2 y SomeClass2 weak-> SomeClass1

protocol SomeProtocol {
    func foo()
}

class SomeClass1: SomeProtocol {
    let someClass2 = SomeClass2()

    init() {
        someClass2.delegate = self
    }

    func foo() {
        print("foo is called")
    }
}

class SomeClass2 {

    weak var delegate: SomeProtocol?

    func onButtonTap() {
        delegate?.foo()
    }
}

Centre de notification

NotificationCenter or NSNotificationCenter(Objective-C) (pas les notifications à distance (Push) ou locales) est une sorte de publish/subscribe event bus . Vous avez NotificationCenter objet singleton qui est un point unique pour n'importe qui pour envoyer ou recevoir un événement. Vous pouvez l'utiliser pour envoyer des événements à travers toute l'application et n'importe qui peut l'interrompre. Un tel système est rapide à développer mais difficile à supporter. C'est aussi une sorte de Loose coupling système.

Vous pouvez utiliser l'API suivante de NotificationCenter :

post(name: object: userInfo:)
addObserver(_ observer: selector: name: object:)
removeObserver(_ observer: selector: object:)

Par exemple, le système affiche ou cache le clavier.

NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

@objc func keyboardWillShow(_ notification:Notification) {
}

@objc func keyboardWillHide(_ notification:Notification) {
}

KVO

KVO - Observation de la valeur d'une clé. Observer les changements de valeur d'une propriété supportée par Objective-C. Vous pouvez l'utiliser lorsque vous avez besoin d'être informé de certains changements sur un objet sans aucune requête.

Objectif-C - @property [À propos] qui utilise willChangeValueForKey y didChangeValueForKey para KVO

*Notes

  • Si vous passez outre willChangeValueForKey , didChangeValueForKey le site observeValueForKeyPath n'est pas tiré
  • Si vous utilisez iVar [À propos] vous êtes responsable d'appeler willChangeValueForKey , didChangeValueForKey

    import "SomeClass.h"

    @interface SomeClass() @property (nonatomic, strong) NSString *someVariable; @end

    @implementation SomeClass

    • (void) foo {
      [self addObserver: self forKeyPath: @"someVariable" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil];

      self.someVariable = @"set someVariable"; }

    • (void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void *)context { if ([keyPath isEqualToString:@"someVariable"]) { NSLog(@"%@", change); } }

    @end

Swift - NSObject y @objc dynamic [À propos]

class SomeClass1 : NSObject {
    @objc dynamic var v = 0
}

class SomeClass2 {
    var kvoToken: NSKeyValueObservation?

    func subscribe(someClass1: SomeClass1) {
        kvoToken = someClass1.observe(\.v, options: .new) { (object, change) in
            guard let value = change.newValue else { return }
            print("New value: \(value)")
        }
    }

    deinit {
        kvoToken?.invalidate()
    }
}

ou

public class SomeClass: NSObject 
    public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

    }
}

func foo() {
    someClass1.addObserver(self, forKeyPath: "v", options: .new, context: nil)
}

[Objective-C KVC vs KVO]
[Swift KVC]

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