2009-07-30 10 views
7

Mam funkcję, którą chcę operować na dwóch różnych niestandardowych obiektach. Moją pierwszą myślą było zaakceptowanie argumentu jako (id) i operowanie na obiekcie id. Nie mogę jednak wydawać się, jak to zrobić.Używanie (id) w Objective-C

Obie klasy (słownie jabłka i pomarańcze) mają zmienne interfejs:

NSDecimalNumber *count; 

chcę zrobić coś podobnego do tego:

-(NSDecimalNumber*)addCount:(id)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 
} 

nie wydaje, aby dowiedzieć się składni spraw, aby to się stało. Czy jest to właściwe podejście, czy byłoby lepiej podklasę (z klasy owoców) i działać na klasie rodzica?

-(NSDecimalNumber*)addCount:(Fruit*)addFruit{ 

    return [count decimalNumberByAdding:addFruit.count]; 
} 

Odpowiedz

12

Mimo że możesz wysłać wiadomość do dowolnego obiektu (id) - osoby korzystające z właściwości wymagają, aby kompilator był świadomy typu, z którym masz do czynienia - jest to spowodowane tym, że obiekty udostępniające właściwości są syntaktycznym cukrem wokół wywoływania konkretnych metod pobierania i ustawiania.

Masz kilka sposobów pracy wokół to:

  1. Zamiast uzyskiwania dostępu do właściwości Count, wezwać odpowiednie [getCount] metod.

  2. Jeżeli różne klasy mają różne wersje tej metody, można użyć czek typ środowiska wykonawczego:

  3. Podaj klasę bazową dla obu typów, dzięki czemu można przejść w coś bardziej konkretnego niż (ID).

  4. Należy zdefiniować i zaimplementować protokół implementujący oba obiekty, który definiuje właściwość count (lub metodę).

Przykład dynamicznego sprawdzania typu:

if([object isKindOfClass:[Apple Class]) 
    // call one overload of getCount 
else if([object isKindOfClass:[Orange Class]) 
    // call another overload of getCount 

Osobiście sprzyjają silne wpisywanie w moim kodu, ponieważ to sprawia, że ​​łatwiej zrozumieć intencję. Pozwala to także IDE wspierać obsługę kodowania za pomocą technologii intellisense, analizy statycznej i funkcji refaktoryzacji. Tak więc w twoim przypadku użyłbym metody 3 lub 4 jako metody zależnej od tego, czy dziedziczenie jest rzeczywiście odpowiednie dla problemu.

+1

Jestem fanem silnego pisania na klawiaturze (poszedłem z # 4 FYI). Dziękuję bardzo za informację; właśnie tego szukałem! –

+0

Jeśli naprawdę potrzebujesz silnego pisania, możesz mieć lepszy czas z językiem statycznym, takim jak C++. Szkoda, że ​​właściwości zachowują się w ten asymetryczny sposób. Przynajmniej powinna istnieć flaga kompilatora, aby umożliwić symetryczne zachowanie kompilacji między składnią właściwości a składnią metoda-odbiornika. – ctpenrose

+0

@ctpenrose Obj-C może być tak samo statycznie napisany jak następny język, jeśli chcesz. – kubi

0

Wysyłasz wiadomość, aby policzyć, co to jest liczba? id jest wskaźnikiem do dowolnego typu obiektu. Jeśli spodziewasz się, że obiekt będzie miał właściwość count, powinieneś mieć możliwość przekazania tylko tablicy (lub innego ograniczenia typu).

-(NSDecimalNumber*)addCount:(NSArray*) Object{ 

return [count decimalNumberByAdding: [Object count]]; 

} 
0

Jak rozumiem, id nie ma żadnych metod i zmiennych związanych z nim, ponieważ jest to ogólny wskaźnik, który nie odnosi się do żadnej konkretnej klasy. This page ma kilka dobrych informacji na temat identyfikatorów, jeśli przewiniesz w dół.

anObject to nie będzie mieć zmienną count, dlatego pierwsza próba nie zadziała. Tworzenie klasy bazowej i używanie jej jako parametru metody wydaje mi się najlepszym pomysłem.

8

Powinieneś spróbować nie uzyskiwać dostępu do zmiennych instancji z innej klasy.

W Objective-C wystarczy, że te dwa obiekty odpowiedzą na ten sam selektor (na przykład count), jednak spowoduje to ostrzeżenie kompilatora.

Istnieją dwa sposoby na pozbycie się tego ostrzeżenia: poprzez podklasę ze wspólnej klasy Fruit lub przez dostosowanie dwóch klas do protokołu. pójdę z protokołu:

@protocol FruitProtocol 

- (NSDecimalNumber *)count; 

@end 

@interface Orange : NSObject<FruitProtocol> 
@end 

@interface Apple : NSObject<FruitProtocol> 
@end 

Następnie metoda może wyglądać następująco:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addFruit { 
    return [count decimalNumberByAdding:[addFruit count]]; 
} 

Tu mówią, że Twój addCount spodziewa dowolny obiekt, który jest zgodny z protokołem FruitProtocol, a tym samym może odpowiadać selektorowi count, aby kompilator go zaakceptował.

+0

wrt/"Nie można uzyskać dostępu do zmiennych instancji z innej klasy." Z pewnością możesz. Jeśli statycznie wpiszesz obiekt, tj. 'Obiekt MYObject * ;, wtedy będziesz mógł uzyskać dostęp do jego zmiennych instancji z dowolnej klasy za pomocą operatora' -> '. Na przykład zakładając, że 'MYObject' ma' int' ivar o nazwie 'count', możesz użyć' int myCount = object-> count; ', aby uzyskać do niego dostęp. Zabezpieczenia dostarczone przez '@ private', itp., Są tylko kosmetyczne, nawet w ObjC2. – johne

+0

To jest świetne! Twoja próbka kodu ułatwiła mi wdrożenie bez dalszego kopania. Dzięki wielkie! –

+0

Masz rację, zmieniam ją na "nie powinieneś". Dziękujemy – pgb

1

To, że próbujesz uzyskać dostęp do "addFruit.count", jest problemem. Składnia kropkowa dotyczy tylko właściwości zadeklarowanych za pomocą @property (lub dla structs). Jeśli go zmienić na

[addFruit count] 

i dodać

-(NSDecimalNumber*)count 
{ 
    return [[count retain] autorelease]; 
} 

do każdej klasy, a następnie będzie działać. Jednak zauważysz, że dostaniesz ostrzeżenie, że "identyfikator" może nie odpowiadać na komunikat "licznika", i jeśli nie możesz być absolutnie pewny, że elementy wysłane do tej metody implementują metodę "liczenia", jest to problematyczne podejście .

Zgadzam się z podejściem pgb. Powinieneś zdefiniować protokół i zadeklarować obie klasy, aby zaimplementować ten protokół. Eliminuje to problem polegający na tym, że nie wiemy, czy obiekt zareaguje na "zliczanie", czy nie, ponieważ obecnie mamy "kontrakt".

Jeśli chcesz zachować składnię kropka z nieruchomości, można zadeklarować je w protokole:

@protocol FruitProtocol 

@property(readonly) NSDecimalNumber * count; 

- (NSDecimalNumber *)count 

@end 

a następnie czynność będzie:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 

} 
+0

Również świetnie! Nie złapałem tego wcześniej. Dzięki za wskazówkę! –

Powiązane problemy