2009-07-23 7 views
36

Mam crack na implementacji powiązań dla mojej własnej podklasy NSView. Działa, ale występują problemy z zachowaniem cykli podczas wiązania z właścicielem pliku z pliku nib. Po krótkim lekturze odkryłem, że Apple miał ten sam problem kilka lat temu, ale naprawił go za pomocą magicznej nieudokumentowanej klasy (NSAutounbinder).Czy można ręcznie zaimplementować wiązania kakao?

Jest długa dyskusja o problemie zachować cyklu tutaj http://www.cocoabuilder.com/archive/message/cocoa/2004/6/12/109600. Rozwiązaniem jest, aby rozwiązać wszystkie powiązania zanim kontroler okno jest wydany, zanim nie jest dealokowane, w takim miejscu windowWillClose :. To wydaje się niepotrzebnym hackem do mnie.

Moje pytanie brzmi: czy istnieje sposób na tworzenie niestandardowych wiązań, które działają tak samo, jak te wykonane przez Apple, bez korzystania z nieudokumentowanych funkcji? Czy podchodzę do tego w niewłaściwy sposób?


UPDATE 2: Znalazłem rozwiązanie, które pozwala ręcznie realizowane dokładnie jak Wiązania Wiązania Apple'a działa. Korzysta z nieudokumentowanej klasy NSAutounbinder, bez korzystania z nieudokumentowanych funkcji. Wczoraj opublikuję rozwiązanie.


UPDATE: Próbowałem za pomocą exposeBinding:, i nie wydaje się żadnej różnicy. Jednak implementacja NSObject z pół działa. Propaguje zmiany od binda do segregatora (tj. Od modelu/kontrolera do widoku), ale nie działa w odwrotny sposób. Ponadto, chociaż oczywiście jest obserwowany obiekt wiążący, nigdy nie jest uruchamiany observeValueForKeyPath:ofObject:change:context:.

Przykład projekt tutaj: http://www.tomdalling.com/wp-content/BindingsTest.zip

dokumentacji Apple oznacza, że ​​nie w rzeczywistości, trzeba zastąpić bind:toObject:withKeyPath:options: wdrożyć ręcznych powiązań. Zobacz tutaj: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html


marginesie: mam badane jak nieudokumentowane NSAutounbinder działa, i oto, co wiem.

Po utworzeniu powiązania z NSWindowController, obiekt związany jest w rzeczywistości NSAutounbinder, który jest pozyskiwany z NSWindowController za pomocą - [NSWindowController _autounbinder]. NSAutounbinder jest nieprzebywalnym proxy dla obiektu NSWindowController. Nie zachowuje się, aby uniknąć problemu z cyklem utrzymania.

Kiedy - [NSWindowController release] zostaje wywołane i retainCount == 1, Nounutounbinder odwiązuje wszystkie wiązania do siebie. Zapewnia to, że przed zwolnieniem nie ma wiszących wskaźników do obiektu.

+0

Podczas gdy CocoaBuilder jest wyłączony, możesz znaleźć odpowiedni wątek na stronie http://lists.apple.com/archives/cocoa-dev/2004//Jun/msg00835.html – s4y

Odpowiedz

21

Oto najlepsze rozwiązanie, jakie mogę znaleźć. Mam bardziej szczegółowe omówienie i demo kod tutaj: http://tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/

Zasadniczo ty nie nadpisanie bind:toObject:withKeyPath:options: lub unbind:. Domyślna implementacja na NSObject będzie używać NSAutounbinder, aby uniknąć cykli zatrzymania. Jak zauważył Louis Gerbarg, nadal istnieją sytuacje, w których NSAutounbinder nie wskakuje. Można jednak sprawić, że twoje powiązania będą działać tak samo dobrze jak powiązania Apple'a.

Ponieważ domyślna implementacja bind:toObject:withKeyPath:options: nie aktualizuje modelu, gdy widok się zmienia, zmiany sterowane widokami muszą być propagowane ręcznie. Możesz użyć -[NSObject infoForBinding:], aby uzyskać wszystkie informacje niezbędne do aktualizacji powiązanego obiektu. Dodałem własne metody na NSObject z kategorii:

-(void)propagateValue:(id)value forBinding:(NSString*)binding; 

obsługuje coraz związanego obiektu, związanego ścieżkę klucza i stosowania transformatora wartość. Implementacja jest dostępna z linku u góry.

+0

Niedawno napisałem odpowiedź na pokrewne pytanie, zanim znalazłem ten wpis. Czy mam rację, że użycie 'exposeBinding:' działa w przypadkach, gdy widok nie musi propagować zmian w modelu? http://stackoverflow.com/questions/366938/is-it-necessary-to-override-bindtoobjectwithkeypathoptions-in-an-nsview-subcl/7394273#7394273 – paulmelnikow

+0

'exposeBinding:' faktycznie nie robi niczego poza Konstruktorem interfejsu Jeżeli dobrze pamiętam. Wszystko, co robi, to sprawić, aby wiązanie pojawiło się w interfejsie GUI budowniczego interfejsu. –

2

Możesz chcieć sprawdzić NSKeyValueBindingCreation Protocol. Umożliwia tworzenie powiązań programowo za pomocą kodu. (Pamiętaj, aby wykonać pracę w trybie awakeFromNib, jeśli chcesz odwoływać się do zmiennych IBOutlet lub ich nie ma.)

+2

Dziękuję za odpowiedź, ale próbuję implementować własne powiązania dla niestandardowej klasy, a nie używać istniejących powiązań. –

+0

Myślę, że to jest właśnie dla + metoda exposeBinding:. Mogę się mylić oczywiście, ale wydaje się, że jest to udokumentowany i usankcjonowany sposób tworzenia własnych wiązań. –

+0

exposedBindings służy tylko do tworzenia wtyczek budowniczych interfejsu z tego, co przeczytałem. –

3

Krótka odpowiedź brzmi: nie, nie możesz go uruchomić bez obejścia kodu wywołującego i stalówki. Nawet NSAutounbinder nie trafia w niektóre przypadki dla NSDocument i NSWindowController, jeśli Apple nie może uzyskać poprawnego działania dla 2 klas, które specjalnie spinają te z nas bez dostępu do wtyczek AppKit w zasadzie nie mają szans.

Po tym, istnieją dwa obejścia, które są być może nieco ładniejsze niż rozłączanie w windowWillClose :.

  1. nie wiążą się z Właścicielem pliku, ale zamiast przeciągnąć NSObjectController jako przedmiot główny poziom do stalówki i wiążą się z tym, czym setContents: na kontrolerze obiektu podczas awakeFromNib.
  2. Włącz usuwanie śmieci. Jeśli jest to opcja, rozwiązuje wszystkie problemy związane z cyklem obiektu ;-) Oczywiście GC wprowadza własne problemy, a jeśli potrzebujesz kompatybilności 10.4, to nie uruchamia się.
2

Zobacz przykład mmalc GraphicsBindings dla dobrego przykładu realizacji własnych powiązań. Aby uruchomić go, musisz wdrożyć nieformalny protokół NSKeyValueBindingCreation. Let Your kontrolery wiedzieć, że są rzeczy, które mogą być przypisane, zadzwoń exposeBinding w + (id) zainicjować metoda widoku:

+ (void)initialize { [self exposeBinding:@"ILIKEBINDAGE"]; } 

Będziesz wtedy potrzeba wdrożenia każdego z wiązaniami zarządzających metod w NSKeyValueBindingCreation protokół. Zasadniczo musisz skonfigurować KVO dla widoku, aby wiedział, kiedy aktualizować na podstawie zachowań aplikacji i obsługi oczyszczenia (rozpinania :).

Jest to bardzo dodatkowy, dość brzydki kod, więc może się zdarzyć, że użycie tradycyjnego kodu kleju działa lepiej i jest łatwiejsze do odczytania.

+1

Przykład GraphicsBindings mmalc ma problem z cyklem podtrzymania, o którym wspomniałem. Ponadto, exposeBinding: zostało omówione w odpowiedzi Ryana Ballantyne'a. –

+2

Niestety, to martwy link. – uchuugaka

Powiązane problemy