2012-08-11 8 views
23

Co to jest użycie parametru kontekstowego w następującej metodzie, która jest używana do rejestracji dla powiadomień o wartości klucza. Dokumentacja po prostu oznacza to jako dowolny zestaw danych.Znaczenie parametru kontekstu w Wartość klucza z obserwacją

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

Czy ktoś może rzucić nieco światła Jaki jest cel za nim ...

Thanks

+0

możliwe duplikat [parametry z observeValueForKeyPath: ofObject: Zmiana: Kontekst:] (http://stackoverflow.com/questions/1625575/parameters-from-observevalueforkeypathofobjectchangecontext) –

Odpowiedz

73

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

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

Teraz postanawiasz, aby MyViewController używać KVO do obserwowania zmian w właściwości center z self.view. Więc należycie dodać siebie jako obserwator:

- (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 wiem, czy UIViewController rejestruje się również jako obserwator self.view „s center. Jeśli tak, możesz mieć dwa problemy:

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

Potrzebujesz sposobu, aby zarejestrować się jako obserwator, który jest odróżnialny od rejestracji KVO na UIViewController. W tym miejscu pojawia się argument context. Musisz podać wartość dla context, że masz absolutną pewność, że UIViewController jest , a nie, używając jako argumentu context. Po wyrejestrowaniu ponownie użyjesz tego samego numeru context, aby usunąć rejestrację, a nie UIViewController. A w twojej metodzie observeValueForKeyPath:ofObject:change:context: musisz sprawdzić, czy wiadomość jest dla ciebie, czy dla twojej superklasy.

Jednym ze sposobów, aby upewnić się, że używasz context, którego nic nie używasz, jest utworzenie zmiennej static w MyViewController.m. Użyj go podczas rejestracji i wyrejestrowania, tak:

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ś nie gwarantowane do kolidować z nadklasy za KVO, jeśli to robi każdy. A jeśli ktoś stworzy podklasę o numerze MyViewController, która również używa KVO, nie będzie kolidować z twoim KVO.

Pamiętaj też, że możesz użyć innego kontekstu dla każdej ścieżki klucza, którą obserwujesz. Następnie, gdy system powiadomi Cię o zmianie, możesz sprawdzić kontekst zamiast sprawdzać ścieżkę klucza. Testowanie wskaźnika równości 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]; 
    } 
} 
+0

Dziękuję dużo za szczegółowe wyjaśnienie .Naprawdę to doceniam. Od jakiegoś czasu zastanawia mnie, dlaczego ten parametr jest ważny, a twoja odpowiedź wyjaśniła to. :) – rustylepord

+0

Witam, mogę użyć kontekstu do ustawienia niektórych obiektów, a później, gdy otrzymam powiadomienie, wykonam określone zadania na podstawie wartości przechowywanej w kontekście. – Sandeep

+9

+1 Doskonałe wyjaśnienie. (Jedno pojedyncze zastrzeżenie: właściwości 'UIView' nie są zgodne z KVO.Nie można obserwować' view.center'.) –

Powiązane problemy