5

Co należy zrobić, aby zaktualizować tableView powiązane z NSArrayController, gdy wywoływana jest metoda, która aktualizuje bazową tablicę? Przykład może to wyjaśnić.NSArrayController i KVO

Po uruchomieniu aplikacji tworzy ona SubwayTrain. Po zainicjowaniu SubwayTrain tworzy pojedynczy SubwayCar. SubwayCar ma zmienną tablicę "pasażerów". Po zainicjowaniu samochodu metra, tworzy się tablica pasażerów i umieszcza się w niej kilka obiektów People (powiedzmy osobę o nazwie "kolekcjoner biletów" i inną, o nazwie "bezdomny facet"). Ci faceci są zawsze na SubwayCar, więc tworzę je podczas inicjalizacji i dodam do tablicy pasażerów.

Podczas życia aplikacji ludzie wsiadają do samochodu. "addPassenger" jest wywoływany w SubwayCar, a osoba przekazana jako argument.

Mam NSArrayController związany z metremTrain.subwayCar.passengers, a przy uruchomieniu mój kolekcjoner biletów i bezdomny facet pojawiają się dobrze. Ale kiedy używam [subwayCar addPassenger:], tableView nie aktualizuje się. Potwierdziłem, że pasażer jest zdecydowanie dodany do tablicy, ale nic nie jest aktualizowane w gui.

Co mogę zrobić źle? Mój instynkt jest taki, że jest związany z KVO - kontroler tablicy nie wie, aby zaktualizować, gdy zostanie wywołany addPassenger (nawet jeśli addPassenger wywołuje [passengers addObject:] .Co mogę się tu dostać źle - mogę opublikować kod, jeśli to pomaga

Dzięki wszystkich chętnych do pomocy.

UPDATE

więc okazuje się, mogę uzyskać to do pracy poprzez zmianę metodą addPassenger z

[seatedPlayers addObject:person]; 

do

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers]; 

[newSeatedPlayers addObject:sp]; 

[seatedPlayers release]; 

[self setSeatedPlayers:newSeatedPlayers]; 

Domyślam się, że to dlatego, że używam [self setSeatedPlayers]. Czy to właściwy sposób? Wydaje się bardzo kłopotliwe, aby skopiować tablicę, zwolnić starą i zaktualizować kopię (w przeciwieństwie do dodawania do istniejącej tablicy).

+0

W jaki sposób widok tabeli jest powiązany z kontrolerem? Czy każda kolumna tabeli jest powiązana z właściwością 'subwayTrain.subwayCar.passengers' (np. Nazwa kolumny powiązana z' subwayTrain.subwayCar.passengers.name')? – outis

+0

tak dokładnie. A nazwiska pasażerów pojawiają się po uruchomieniu. –

Odpowiedz

1

więc okazuje się, mogę uzyskać to do pracy poprzez zmianę metodą addPassenger z

[seatedPlayers addObject:person]; 

do

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers]; 
[newSeatedPlayers addObject:sp]; 
[seatedPlayers release]; 
[self setSeatedPlayers:newSeatedPlayers]; 

to chyba dlatego, że używam [self setSeatedPlayers]. Czy to właściwy sposób?

Po pierwsze, jest to setSeatedPlayers:, z dwukropkiem. Jest to niezwykle ważne w Objective-C.

Używanie własnych seterów to właściwy sposób, ale używasz niewłaściwej, prawidłowej metody. Działa, ale wciąż piszesz więcej kodu, niż potrzebujesz.

Co należy zrobić, to zaimplementować zestawy akcesorów, takie jak addSeatedPlayersObject:. Następnie wyślij tę wiadomość. To sprawia, że ​​dodanie ludziom krótkie jedno-liner:

[self addSeatedPlayersObject:person]; 

i tak długo, jak postępować the KVC-compliant accessor formats, będziesz otrzymywać powiadomienia KVO za darmo, tak samo jak z setSeatedPlayers:.

Zalety tego ponad setSeatedPlayers: są:

  • Kod mutować zestaw będzie krótszy.
  • Ponieważ jest krótszy, będzie czystszy.
  • Korzystanie ze specjalnych akcesorów do ustawiania mutacji zapewnia możliwość określonych powiadomień KVO o ustawionej mutacji, zamiast ogólnych powiadomień o zmienionych ustawieniach.

Też wolę to rozwiązanie od mutableSetValueForKey:, zarówno ze względu na zwięzłość, jak i dlatego, że tak łatwo jest błędnie przeliterować klucz w tym ciągu literałowym. (Uli Kusterer has a macro to cause a warning when that happens, co jest przydatne, kiedy naprawdę trzeba mówić do KVC lub samego KVO.)

7

Nie wiem, czy jest uważany za błąd, ale addObject: (i removeObject: atIndex :) nie generuje powiadomień KVO, dlatego widok kontrolera/tabeli tablicy nie jest aktualizowany. Być zgodny z KVO, użyj mutableArrayValueForKey:

Przykład:

[[self mutableArrayValueForKey:@"seatedPlayers"] addObject:person]; 

Warto również wdrożyć insertObject: inSeatedPlayersAtIndex: od domyślnej metody KVO są bardzo powolne (oni stworzyć zupełnie nową tablicę, dodać celem tej tablicy i ustaw oryginalną tablicę do nowej tablicy - bardzo nieefektywne)

- (void)insertObject:(id)object inSeatedPlayerAtIndex:(int)index 
{ 
    [seatedPlayers insertObject:object atIndex:index]; 
} 

pamiętać, że ta metoda będzie także wywoływana, gdy kontroler dodaje tablica obiektów, więc jego też ładny hak na myśli jak rejestracja operacji cofania itp.

1

Ja nie próbowałem, więc nie mogę powiedzieć, że to działa, ale nie otrzymywać powiadomienia KVO wywołując

insertObject: atArrangedObjectIndex:

na ArrayController?

+0

Tak, użycie kontrolera NSArrayController do zmutowania tablicy powoduje, że NSArrayController wie o mutacji, a ona (i powiązane z nią elementy) powinna zostać odpowiednio zaktualizowana. – ipmcc

0
  1. Zastosowanie willChangeValueForKey: i didChangeValueForKey: owinięty wokół zmiany członka gdy zmiana nie wydaje się powodować powiadomienie KVO. Jest to przydatne, gdy bezpośrednio zmieniasz zmienną instancji.

  2. Użyj willChangeValueForKey:withSetMutation:usingObjects: i didChangeValueForKey:withSetMutation:usingObjects: owiniętych wokół zmiany zawartości kolekcji, gdy zmiana nie wydaje się powodować powiadomienia KVO.

  3. Użyj skrótu [seatedPlayers setByAddingObject:sp], aby uniknąć niepotrzebnego przydzielania zestawu zmiennego.

Ogólnie rzecz biorąc, ja też w ten sposób:

[self willChangeValueForKey:@"seatedPlayers" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:sp]; 
[seatedPlayers addObject:sp]; 
[self didChangeValueForKey:@"seatedPlayers" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:sp]; 

lub poniżej:

[self setSeatedPlayers:[seatedPlayers setByAddingObject:sp]]; 

z drugiej alternatywy, powodując automatyczne wywołanie funkcji podanych w punkcie 1. Alternatywnie pierwszy powinna być lepiej wykonana niż.

1

Kluczem do magii Key Value Observing jest Key Value Compliance. Początkowo używano nazwy metody addObject: która jest powiązana tylko z "nieuporządkowanym wzorcem akcesoriów", a właściwość jest własnością indeksowaną (NSMutableArray). Po zmianie właściwości na nieuporządkowaną właściwość (NSMutableSet) zadziałało. Rozważ NSArray lub NSMutableArray do indeksowania właściwości, a NSSet lub NSMutableSet do właściwości nieuporządkowanych. Naprawdę musisz przeczytać tę część uważnie, aby wiedzieć, co jest wymagane, aby magia się zdarzyła ... Key-Value-Compliance. Istnieje kilka "Wymaganych" metod dla różnych kategorii, nawet jeśli nie planujesz ich użyć.