Do czego służy parametr kontekstowy w obserwacji wartości klucza

Jakie jest zastosowanie parametru kontekstowego w następującej metodzie, która jest używana do rejestracji powiadomień o wartości klucza. Dokumentacje po prostu oznacza to jako dowolny zestaw danych.

addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil
Czy ktoś może rzucić trochę światła na to, jaki jest cel ...
Author: Honey, 2012-08-11

1 answers

Mam nadzieję, że to wyjaśnienie nie jest zbyt abstrakcyjne, aby zrozumieć.

Załóżmy, że tworzysz klasę MyViewController, która jest podklasą UIViewController. Nie masz kodu źródłowego UIViewController.

Teraz zdecydujesz się MyViewController użyć KVO do obserwowania zmian w center właściwości self.view. Więc należycie dodajesz siebie jako obserwatora:

- (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];
}

Problem polega na tym, że nie wiesz, czy UIViewController rejestruje się również jako obserwator self.view's center. Jeśli tak, to możesz mieć dwa problemy:

  1. możesz zostać wywołany dwa razy, gdy zmieni się centrum widoku.
  2. kiedy usuniesz siebie jako obserwatora, możesz również usunąć UIViewController rejestrację KVO.

Potrzebujesz sposobu zarejestrowania siebie jako obserwatora, który jest odróżnialny od UIViewController rejestracji KVO. Tutaj pojawia się argument context. Musisz przekazać wartość context, która jest absolutnie pewna UIViewController jest , a nie używaną jako argument context. Kiedy ty Wyrejestruj się, używasz tego samego context ponownie, aby usunąć tylko swoją rejestrację, a nie rejestrację UIViewController. W metodzie observeValueForKeyPath:ofObject:change:context: musisz sprawdzić context, aby sprawdzić, czy wiadomość jest dla Ciebie, czy dla Twojej superklasy.

Jednym ze sposobów na upewnienie się, że używasz context, którego nic innego nie używa, jest utworzenie static zmiennej w MyViewController.m. Użyj go podczas rejestracji i wyrejestrowania, w ten sposób:

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];
}

Następnie w metodzie observeValueForKeyPath:..., sprawdź to tak:

- (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];
    }
}

Teraz jesteś gwarantuję, że nie będzie ingerować w KVO Twojej superklasy, jeśli to zrobi. A jeśli ktoś stworzy podklasę MyViewController, która również używa KVO, nie będzie ingerować w twoje KVO.

Zauważ również, że możesz użyć innego kontekstu dla każdej ścieżki kluczowej, którą obserwujesz. Następnie, gdy system powiadomi Cię o zmianie, Możesz sprawdzić kontekst zamiast sprawdzania kluczowej ścieżki. Testowanie równości wskaźników jest trochę szybsze niż sprawdzanie równości łańcuchów. Przykład:

- (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];
    }
}
 74
Author: rob mayoff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-21 20:26:14