28 Stimmen

Wofür wird der Kontextparameter in Key value observing verwendet?

Was ist die Verwendung des Kontextparameters in der folgenden Methode, die zur Registrierung für Schlüsselwertmeldungen verwendet wird. In der Dokumentation wird er einfach als beliebiger Satz von Daten bezeichnet.

addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil

Kann mir jemand sagen, was der Zweck dahinter ist ...

79voto

rob mayoff Punkte 356759

Ich hoffe, diese Erklärung ist nicht zu abstrakt, um sie zu verstehen.

Angenommen, Sie erstellen eine Klasse MyViewController , die eine Unterklasse von UIViewController . Sie haben nicht den Quellcode von UIViewController .

Nun beschließen Sie, eine MyViewController KVO verwenden, um Änderungen an der center Eigenschaft von self.view . Sie fügen sich also ordnungsgemäß als Beobachter ein:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.view addObserver:self forKeyPath:@"center" options:0 context:NULL];
}

- (void)viewDidDisappear:(BOOL)animated {
    [self.view removeObserver:self forKeyPath:@"center"];
    [super viewDidDisappear:animated];
}

Das Problem dabei ist, dass Sie nicht wissen, ob UIViewController meldet sich auch als Beobachter von self.view 's center . Wenn dies der Fall ist, dann haben Sie möglicherweise zwei Probleme:

  1. Sie werden möglicherweise zweimal aufgerufen, wenn sich der Mittelpunkt der Ansicht ändert.
  2. Wenn Sie sich selbst als Beobachter entfernen, können Sie auch die UIViewController der KVO-Registrierung.

Sie brauchen eine Möglichkeit, sich als Beobachter zu registrieren, die sich von UIViewController der KVO-Registrierung. Das ist der Punkt, an dem die context Argument kommt. Sie müssen einen Wert für context dass Sie sich absolut sicher sind UIViewController est no mit als context Argument. Wenn Sie die Registrierung aufheben, verwenden Sie das gleiche context wieder, damit Sie nur Ihre Registrierung entfernen, nicht UIViewController Registrierung. Und in Ihrem observeValueForKeyPath:ofObject:change:context: Methode, müssen Sie die context um festzustellen, ob die Nachricht für Sie oder für Ihre Oberklasse bestimmt ist.

Eine Möglichkeit, um sicher zu sein, dass Sie eine context die nichts anderes verwendet, ist die Schaffung eines static variabel in MyViewController.m . Verwenden Sie es, wenn Sie sich an- und abmelden, etwa so:

static int kCenterContext;

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.view addObserver:self forKeyPath:@"center" options:0 context:&kCenterContext];
}

- (void)viewDidDisappear:(BOOL)animated {
    [self.view removeObserver:self forKeyPath:@"center" context:&kCenterContext];
    [super viewDidDisappear:animated];
}

Dann in Ihrem observeValueForKeyPath:... Methode, überprüfen Sie es wie folgt:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
{
    if (context == &kCenterContext) {
        // This message is for me.  Handle it.
        [self viewCenterDidChange];
        // Do not pass it on to super!
    } else {
        // This message is not for me; pass it on to super.
        [super observeValueForKeyPath:keyPath ofObject:object
            change:change context:context];
    }
}

Jetzt ist gewährleistet, dass Sie die KVO Ihrer Oberklasse nicht beeinträchtigen, falls sie überhaupt eine hat. Und wenn jemand eine Unterklasse von MyViewController der auch KVO verwendet, wird es Ihre KVO nicht beeinträchtigen.

Beachten Sie auch, dass Sie für jeden Schlüsselpfad, den Sie beobachten, einen anderen Kontext verwenden können. Wenn das System Sie dann über eine Änderung informiert, können Sie den Kontext prüfen, anstatt den Schlüsselpfad zu prüfen. Die Prüfung auf Zeigergleichheit ist etwas schneller als die Prüfung auf Stringgleichheit. Beispiel:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
{
    if (context == &kCenterContext) {
        [self viewCenterDidChange];
        // Do not pass it on to super!
    } else if (context == &kBackgroundColorContext) {
        [self viewBackgroundDidChange];
        // Do not pass it on to super!
    } else if (context == &kAlphaContext) {
        [self viewAlphaDidChange];
        // Do not pass it on to super!
    } else {
        // This message is not for me; pass it on to super.
        [super observeValueForKeyPath:keyPath ofObject:object
            change:change context:context];
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X