2010-11-18 12 views
5

Zacząłem programować iPhone'y około miesiąc temu, a strona okazała się bardzo przydatna. Więc jeśli ktoś tam może mi pomóc.Wysyłanie danych między klasami w kakaowym Objective C

Myślę, że rozumiem podstawy, w jaki sposób @property i @synthesise działają i używają ustawiających i pobierających, ale mam problem.

Powiedz, że mam 3 klasy: funkcje, Class1 i Class2.

Funkcje to klasa przechowująca wszystkie dane, a Klasa1 i Klasa2 odczytują z niej dane i zapisują do niej nowe dane (zmieniają dane). Jednak zarówno Class1, jak i Class2 będą tworzyć własne instancje funkcji, ponieważ jest to po prostu plan danych.

Jeśli więc klasa 1 zapisuje lub "ustawia" niektóre dane (powiedzmy) 5 do funkcji i klasy2 "dostaje" je, klasa2 odzyska 0, ponieważ klasa 1 napisała 5 tylko do swojej instancji funkcji, których klasa2 nie widzi .

Przypuszczam, że po pierwsze, czy to prawda? Po drugie, w jaki sposób mogę to zrobić, aby Class1 i Class2 mogły wyświetlać te same dane do pobrania i ustawienia.

Dzięki za pomoc. Rozumiem, że może to być temat, którego jeszcze się nie nauczyłem, ale jeśli tak, to chciałbym wiedzieć, co to jest, więc mogę to zrobić.

Odpowiedz

6

Masz kilka opcji, z których wszystkie opierają się na zapewnieniu, że Class1 i Class2 używają tego samego wystąpienia "obiektu udostępnionego".

  1. Wyraźnie przekazuj tę samą instancję do klasy 1 i klasy 2 z zewnątrz, zamiast zezwalać klasie 1 i klasie 2 na tworzenie samej instancji; lub
  2. Należy podać inicjator singletonu do klasy Functions, a następnie upewnić się, że Class1 i Class2 używają tego; lub
  3. Użyj wzorca projektowego znanego jako wzorzec rejestru i upewnij się, że klasy 1 i klasa 2 pobierają instancję klasy funkcji z rejestru; lub
  4. Użyj zależnego wtrysku (złożonego).

Scenariusz (1) jest najprostszym do zrozumienia, ponieważ idzie dokładnie tak:

Functions *funcs = [[Functions alloc] init]; 

Class1 *obj1 = [[Class1 alloc] initWithFunctions:funcs]; 
Class2 *obj2 = [[Class2 alloc] initWithFunctions:funcs]; 
/* or alternatively use setters after initialization */ 

Scenariusz (2) jest kolejnym najprostszym i jest bardzo powszechne. Kakao zapewnia inicjatory singletonowe dla wielu jego klas. Za każdym razem, gdy widzisz +shared... jako prefiks dla inicjalizatora, prawdopodobnie zwraca on singleton.

@implementation Functions 

+(id)sharedFunctions { 
    static Functions *sharedFunctions = nil; 

    @synchronized(self) { 
    if (sharedFunctions == nil) { 
     sharedFunctions = [[self alloc] init]; 
    } 

    return sharedFunctions; 
    } 
} 

@end 

Zmienna statyczna jest inicjowana tylko raz, co oznacza, że ​​można leniwie załadować instancję obiektu do niego za pomocą czek na jego wartość początkową (który występuje tylko raz). Każde kolejne wywołanie metody zwraca tę samą instancję.

Functions *f1 = [Functions sharedFunctions]; 
Functions *f2 = [Functions sharedFunctions]; 

/* f1 == f2; */ // always 

Wariant (3) nie są bardzo widoczne w cel-C w porównaniu z innymi językami i realizuje wiele tych samych celów jak pojedyncza. Chodzi o to, że masz słownik obiektów, które można wyszukać za pomocą klucza. Wszystko, co wymaga dostępu do elementów w rejestrze, prosi rejestr o własną instancję. Zazwyczaj rejestr byłby singleton.

Opcja (4), zastrzyk zależności, jest bardzo eleganckim rozwiązaniem z wieloma korzyściami kosztem dodatkowej złożoności. Korzyści wynikają z faktu, że masz pewność, że zależności są zawsze luźno powiązane (co sprawia, że ​​wymienianie implementacji i testowanie zależności jest o wiele prostsze). Złożoność wynika z niestandardowych mechanizmów pobierania instancji tego, czego potrzebujesz.

Wstrzykiwanie zależności dotyczy pomysłu, że żaden obiekt nie tworzy własnych zależności. Zamiast polegać na czymś innym, aby zapewnić te zależności. To "coś innego" jest znane jako pojemnik z wtryskiem zależności. Kontener wstrzykiwania zależności jest faktycznie warstwą na wierzchu wzorca rejestru, ponieważ kontener będzie albo przechowywać wstępnie zbudowane instancje zależności, albo będzie wiedział, jak utworzyć instancje nowych instancji.

W najprostszym przypadku iniekcja zależności jest dokładnie tym, co zademonstrowałem w opcji (1). Do tego celu nie potrzebujesz nawet kontenera do iniekcji zależności.

Przesuwając poziom złożoności, wtrysk zależności wprowadza pojęcie kontenera DI, który obejmuje kilka istniejących wzorców projektowych (rejestr, jak widać w opcji (3), singleton (prawdopodobnie, ale nie ściśle)) i fabryki (aby dowiedzieć się, jak tworzyć nowe instancje obiektów, którymi zarządza).

Demonstrowanie pełnego wdrożenia kontenera DI prawdopodobnie wykraczałoby poza zakres tego pytania, ale z punktu widzenia interfejsu publicznego, jedna realizacja może wyglądać następująco:

DIContainer *container = [DIContainer sharedContainer]; 

[container registerClass:[ClassA class]]; 
[container registerClass:[ClassB class]]; 
[container registerDependentProperty:@selector(setClassA:) 
         withInstanceOf:[ClassA class] 
          forClass:[ClassB class]]; 

ClassB *obj = [container makeInstanceOfClass:[ClassB class]]; 
NSLog(@"ClassB's -classA type = %@", [[obj classA] class]); 

po prostu wpisane, że od szczytu głowy w w środku tego postu, więc nie zakładaj, że jest on w 100% dokładny, ale masz pojęcie. Kontener został poinformowany, że podczas inicjowania wystąpień klasy B musi wywołać -setClassA:, używając instancji ClassA, którą również inicjuje zgodnie z regułami zdefiniowanymi w kontenerze (w tym przypadku nie ma zależności od ClassA, więc po prostu zwraca zwykły przypadek

Zażycie nic więcej od tej odpowiedzi, ale należy pamiętać opcje (1) i (2);).

+2

Pozdrawiam człowieka, to naprawdę przydatne. Poszedłem na opcję 2 i działa dobrze. Opcje 3 i 4 trochę przeszły mi przez głowę, ale ponownie przeczytam je jutro po tym, jak trochę się przespałem. Rano może mieć sens. Dzięki za pomoc, bardzo przydatne. :-D – Baza207

+1

Nie ma problemu, uważam, że wybór opcji (2) jest dobry.Opcja (1) jest "technicznie" najlepsza, ponieważ singleton ma pewną złą reputację wśród wielu programistów, ze względu na trudność, z jaką można ją przetestować (nieczyste środowisko testowe). Jednak poprawnie użyte jest idealnie. W rzeczywistości, ponieważ Objective-C nie ma jednego ekskluzywnego inicjalizatora/konstruktora, jak inne języki, singleton nie jest w 100% wymuszony, tak więc można go wykorzystać w testowaniu w każdym przypadku. Opcja 3 jest dość prosta, ale tak, opcja (4) to temat, który wprawia w zakłopotanie nawet doświadczonych programistów. – d11wtq

+0

Wiem, że to pytanie jest stare, ale pomogło mi to całkowicie. +1 –

0

To jest naprawdę bardziej pytanie o programowanie obiektowe w ogóle, ale rozwiązanie dotyczy także Objective-C. To, co chcesz zrobić, to stworzyć jedną instancję funkcji. Ta instancja powinna być współużytkowana między instancjami klasy 1 i klasy 2.

Functions *f = [[Functions alloc] init]; 
Class1 *c1 = [[Class1 alloc] init]; 
Class2 *c2 = [[Class2 alloc] init]; 
// set the value of a instance variable of f to the value of aValue from c1 
[f setSomeValue:[c1 aValue]]; 
// now change it to c2's aValue 
[f setSomeValue:[c2 aValue]]; 
+0

OK, to ma sens. Zgaduję więc, że w pliku Class1 umieściłbyś tylko bity z Class1 i umieszczał tylko bity z Class2 w pliku Class2. Chociaż init instancja Functions idzie w obu? Przepraszam, jeśli powtarzam różne rzeczy, ale ciągle to robię i mój umysł jest trochę podniecony. – Baza207

0

Istnieje wiele odniesień on-line tam, ale znalazłem to książka to wielki atut. Programowanie w Objective-C 2.0 (wydanie 2) przez Stephena G. Kochana. To świetne miejsce startowe.

Powiązane problemy