2008-11-24 10 views
15

Pracuję nad fabryką obiektów, aby śledzić małą kolekcję obiektów. Obiekty mogą być różnych typów, ale wszystkie będą odpowiadać na createInstance i reset. Obiekty nie mogą pochodzić ze wspólnej klasy bazowej, ponieważ niektóre z nich będą musiały pochodzić z wbudowanych klas kakao, takich jak NSView i NSWindowController.Jak mogę przekazać nazwę klasy jako argument do fabryki obiektów w kakao?

Chciałbym, aby móc tworzyć wystąpień dowolnego odpowiedniego obiektu, po prostu przechodząc żądaną classname do mojej fabryki w następujący sposób:

myClass * variable = [factory makeObjectOfClass:myClass];

Sposób makeObjectOfClass: będzie wyglądać mniej więcej tak:

- (id)makeObjectOfClass:(CLASSNAME)className 
{ 
    assert([className instancesRespondToSelector:@selector(reset)]); 
    id newInstance = [className createInstance]; 
    [managedObjects addObject:newInstance]; 
    return newInstance; 
}

Czy istnieje sposób przekazania nazwy klasy do metody, tak jak zrobiłem to z argumentem (CLASSNAME)className powyżej makeObjectOfClass:?

W trosce o kompletność, oto dlaczego chcę zarządzać wszystkimi przedmiotami. Chcę móc zresetować komplet obiektów w jednym ujęciu, dzwoniąc pod numer [factory reset];.

- (void)reset 
{ 
    [managedObjects makeObjectsPerformSelector:@selector(reset)]; 
}
+0

Jestem rozdarta pomiędzy Michael Tsai i odpowiedzi Matt Gallagher. Przegłosowałem oba, ponieważ obie wspominają o użyciu "klasy", której właśnie szukałem. Ostatecznie wybrałem odpowiedź Matta, ponieważ podkreśla ona "Class" nad ClassFromString i jako pierwsza wymieniła użycie "Class" przed edycją. –

+0

@Ned Batchelder: Dziękujemy za zmianę tagu. Z jakiegoś powodu "targetc" pokazuje o wiele więcej pozycji (około 200) niż "cel-c" z rozwijanej listy tagów pojawiających się po dodaniu tagów do pytania, ale teraz widzę, że "objectc" został przekierowany do 'celu-c' –

+0

@eJames: Twoje pytanie się pokazuje -reset jest wysyłany do instancji, a nie do obiektu klasy, więc myślę, że [aClass odpowiadaToSelektor: @selector (reset)] w odpowiedzi Matta Gallaghera jest niepoprawne. –

Odpowiedz

22

można przekonwertować ciąg do klasy przy użyciu funkcji: NSClassFromString

Class classFromString = NSClassFromString(@"MyClass"); 

W twoim przypadku jednak, że będziesz lepiej wyłączyć za pomocą klasa obiektów bezpośrednio.

MyClass * variable = [factory makeObjectOfClass:[MyClass class]]; 

- (id)makeObjectOfClass:(Class)aClass 
{ 
    assert([aClass instancesRespondToSelector:@selector(reset)]); 
    id newInstance = [aClass createInstance]; 
    [managedObjects addObject:newInstance]; 
    return newInstance; 
} 
+0

Typ "Klasa" i [klasa MyClass] są dokładnie tym, czego szukałem. Dziękuję Ci! –

+0

Michael Tsai zwrócił uwagę, że linia [aClass respondsToSelector: @selector (reset)] powinna zamiast tego odczytać [aClass instancesRespondToSelector: @selector (reset)]. Dokonuję zmiany w moim pytaniu, możesz chcieć zrobić to samo w swojej odpowiedzi. –

2

Brzmi to jak chcesz coś takiego:

- (id)makeObjectOfClassNamed:(NSString *)className 
{ 
    Class klass = NSClassFromString(className); 
    assert([klass instancesRespondToSelector:@selector(reset)]); 
    id newInstance = [klass createInstance]; 
    [managedObjects addObject:newInstance]; 
    return newInstance; 
} 

byłoby przyjąć metody klasy o nazwie +createInstance. Lub możesz po prostu użyć [[klass alloc] init].

nazwać:

MyClass *variable = [factory makeObjectOfClassNamed:@"MyClass"]; 

W zależności od tego, co próbujemy zrobić, to może być lepiej, aby przejść wokół obiektów klasy niż strun, np:

MyClass *variable = [factory makeObjectOfClass:[MyClass class]]; 
+0

Dziękuję za odpowiedź. Będę używał podejścia [klasy MyClass], o którym wspomniałeś w swojej edycji. –

+0

Jeśli nie kompilujesz w Objective-C++, możesz nazwać zmienne "class". – cncool

3

Jest to dość łatwe do dynamicznie określ klasę, w rzeczywistości możesz po prostu odwoływać się do niej według jej nazwy:

id string = [[NSClassFromString(@"NSString") alloc] initWithString:@"Hello!"]; 
NSLog(@"%@", string); 

Jeszcze jedna wskazówka, chciałbym void za pomocą nomenklatury "obiekt zarządzany", ponieważ większość innych programistów Cocoa odczyta to jako NSManagedObject, z Core Data. Możesz również łatwiej korzystać z globalnej NSNotification (zamiast subskrypcji wszystkich obiektów, które można zresetować) zamiast zarządzać zbiorem różnych typów obiektów, ale jesteś bardziej poinformowany, aby podjąć taką decyzję niż ja.

+0

dobry punkt o NSManagedObject. Zmienię moje pytanie, aby uniknąć ewentualnego zamieszania. –

3

Bit of odpowiedź brakuje innych odpowiedzi jest to, że można zdefiniować @protocol zawierający swoje +createInstance i +reset metod.

+0

Dziękuję za napiwek! Mam zamiar użyć protokołu, ale nie odczuwałem potrzeby, aby o nim wspomnieć. –

Powiązane problemy