2012-03-08 12 views
5

Próbuję obserwować zmiany w słowniku za pomocą KVO.NSMutableDictionary KVO

przykład:

dictionary = [NSMutableDictionary new]; 
[dictionary setObject:@"test1" forKey:@"key1"]; 
[dictionary setObject:@"test2" forKey:@"key2"];  
[dictionary setObject:@"test3" forKey:@"key1"]; 

chęcią, aby móc podłączyć się do obserwatora, gdy wartości są dodawane do słownika. usunięte lub zastąpione (czyli w powyższych przypadkach, gdy każdy z metod setObject się nazywa)

Tak na zakończenie: Chcę funkcja mieć

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 

nazwie kiedy dodać każdy nowy wpis do słownika lub Usuń dowolny wpis lub WYMIENIAJ dowolny wpis.

NOT: NIE chcę określać, które klawisze obserwuję. (np. obserwuj tylko, gdy @ "key1" jest dodany), ponieważ to rozwiązanie nie jest skalowane.

+0

Co się stanie, jeśli zauważysz klawisz '@" @ count "' w słowniku? –

+0

Nie. Nie działa. Jeśli zastąpię @ "@ count" przez @ "key2", to działa, ale to nie jest jednoznaczne rozwiązanie. –

Odpowiedz

0

Nie możesz podklasować NSMutableDictionary i zastąpić różnych ustawiaczy? Na przykład, przesłonięcie setObject: forKey: przez wywołanie super, a następnie natychmiastowe wywołanie addObserver ...

Możesz również napisać wrapper dla NSMutableDictionary, w którym zmusisz się do użycia niestandardowych ustawiaczy do manipulowania bazowym NSMutableDictionary.

Może potrzebuję więcej kontekstu do któregokolwiek z twoich ograniczeń lub intencji skalowalności.

+0

Nielegalne jest przesłonięcie NSMutableDictionary (ku mojemu zaskoczeniu). Wywołanie [super SetObject: forKey:] powoduje wyjątek mówiąc coś o klasie abstrakcyjnej. Pochylam się nad kompozycją i ponownie wdrażam wszystkie funkcje, które może zapewnić słownik (PITA i brak polimorficzny). Problem skalowalności polegał na tym, że można tylko obserwować zmiany w "key1" w słowniku, a nie "*" zmiany w słowniku. Nie mogę więc powiadomić obserwatora, jeśli do słownika zostanie dodany nowy klucz. –

+0

Interesujące naprawdę. Do tej pory uważam, że klasa dekoratorów może być najlepszą opcją. Nie musisz jednak ponownie wdrażać wszystkich metod. Możesz po prostu mieć słownik jako członek i wywoływać [myObject.dictionary nsdictionarymethod] dla jakichkolwiek operacji nie-kvo I tylko ponownie zaimplementować dodawanie, ustawianie, usuwanie metod. – Vinnie

7

Podklasy NSMutableDictionary jest nieco denerwujące, ze względu na to, że NSDictionary i jego przyjaciele są klastrami klas. Jest to z pewnością wykonalne, a jeśli musisz przekazać obiekt do innego zestawu klas, możesz to zrobić. W przeciwnym razie łatwiej byłoby utworzyć klasę złożoną, która ma ten sam podstawowy interfejs API i wewnętrznie używa obiektu NSMutableDictionary do przechowywania. Jest całkiem niezłe zapisanie jako CocoaWithLove.com, Ordered Dictionary Subclassing, które idzie w tym kierunku.

Jednak to nie rozwiązuje całkowicie twojego problemu. Sugerowałbym, że zaczynasz od klasy podklasy lub klasy dekoratora, takiej jak ta powyżej, a następnie dodawaj obsługę wyraźnie dla -(NSArray*)allKeys, która jest standardowym akcesoriem samego siebie w samej NSDictionary. Następnie możesz dodać obsługę przekazywania komunikatów zmian dla allKeys, co umożliwi obserwację.

Można to zrobić, dodając następujący kod wokół metod -setObject:forKey: i -removeObjectForKey:.

- (void)setObject:(id)anObject forKey:(id)aKey 
{ 
    BOOL addKey=NO; 
    if (![dictionary objectForKey: aKey]) { 
     addKey=YES; 
     [self willChangeValueForKey: @"allKeys"]; 
    } 
    [dictionary setObject:anObject forKey:aKey]; 
    if (addKey) 
     [self didChangeValueForKey: @"allKeys"]; 
} 

- (void)removeObjectForKey:(id)aKey 
{ 
    [self willChangeValueForKey: @"allKeys"]; 
    [dictionary removeObjectForKey:aKey]; 
    [self didChangeValueForKey: @"allKeys"]; 
} 

Co jest wykonywana jest tutaj to, że jesteśmy dodanie wyraźnego powiadomienia KVO do klasy, kiedy klucze słownika są zmieniane, aby zaznaczyć zmianę tablicy.

To zajmie dodawanie i usuwanie. Jeśli chcesz, aby zmiany zostały zgłoszone na tej samej podstawie, można usunąć, jeśli sprawozdania, i po prostu AllKeys klasy powiadamia o albo ustawić lub usunąć w następujący sposób:

- (void)setObject:(id)anObject forKey:(id)aKey 
{ 
    [self willChangeValueForKey: @"allKeys"]; 
    [dictionary setObject:anObject forKey:aKey]; 
    [self didChangeValueForKey: @"allKeys"]; 
} 

Następnie w kodzie, należy umieścić w jeden obserwator dla klucza @ "allKeys" na tym obiekcie, a będziesz otrzymywać powiadomienia o każdej zmianie przedmiotu.

+0

Zgadzam się z tym wnioskiem. Dzięki gaige. Zamierzam to wdrożyć. –

+0

Jeśli to zadziała, nie zapomnij zagłosować na odpowiedzi, które uznałeś za pomocne, i oznacz jako takie, które dostarczyły rozwiązanie. – gaige

+0

Gdy rozmiar NSMutableDictionary rośnie, czy metody te nie będą wywoływane ponownie dla każdego klucza? –

0

Mam nadzieję, że będą pomocne

- (void)addObserver:(id)observer { 
    for (id key in grid) 
     [self addObserver:observer 
       forKeyPath:[key description] 
        options:0 
        context:key]; 
} 
0

myślę inny sposób to zrobić przy użyciu poniższego nadpisanie, okrywać obserwujemy NSMutableDictionary „allRecentCurrencyData”, której wartości są zależne od recentBrazilReals, recentEuEuro, recentUkPounds, recentJapanYen , obserwator zostanie wezwany, ale wadą jest to, że musisz znać klucze przed tym, aby to zrobić.

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key 
{ 
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; 

    if ([key isEqualToString:@"allRecentCurrencyData"]) { 
     NSArray *affectingKeys = @[@"recentBrazilReals", @"recentEuEuro",@"recentUkPounds",@"recentJapanYen"]; 
     keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys]; 
    } 
    return keyPaths; 
} 
1

I rozwiązać podobny problem dodając obserwatora na zmienny słownik „tłumacza” w ten sposób:

[self addObserver:self forKeyPath:@"[email protected]" options:0 context:NULL]; 

Moja aplikacja zarządza dane w sposób klasyczny, stosując tableview, A kontroler i słownik jako własność KVO "tłumacz". Słownik jest powiązany z kontrolerem NSDictionaryController w moim XIB, a treść widoku tabeli jest powiązana z kontrolerem.

To są połączenia z tableview:

enter image description here

Teraz w każdym z następujących przypadków złapię zmiany:

  • dodając parę klucz-wartość
  • usuwając para klucz-wartość
  • zmiana klucza
  • changi ng wartość

Uwaga: niestety to podejście nie działa z NSMutableArrays. Zmiany nie są rozpoznawane