2009-01-21 9 views

Odpowiedz

51

Ze zmienną wpisaną na id można wysłać jej wiadomość, a kompilator nie złoży reklamacji. Ze zmienną typu NSObject * można wysyłać tylko komunikaty zadeklarowane przez NSObject (nie metody jakiejkolwiek podklasy), ponieważ spowoduje to wygenerowanie ostrzeżenia. Ogólnie rzecz biorąc, chcesz uzyskać id.

Dalsze wyjaśnienie: Wszystkie obiekty są zasadniczo typu id. Punktem deklarowania typu statycznego jest przekazanie kompilatorowi: "Załóżmy, że ten obiekt jest członkiem tej klasy." Więc jeśli wyślesz mu wiadomość, której klasa nie deklaruje, kompilator może powiedzieć: "Czekaj, ten obiekt nie powinien dostać tej wiadomości!" Ponadto, jeśli dwie klasy mają metody o tej samej nazwie, ale o różnych sygnaturach (to jest typach argumentów lub zwracanych), można je zgadnąć, którą metodę oznacza klasa, którą zadeklarowałeś dla zmiennej. Jeśli zostanie zadeklarowany jako id, kompilator po prostu podniesie ręce i powie: "OK, nie mam wystarczających informacji tutaj." Wybieram podpis metody losowo. " (To generalnie nie będzie pomagał deklarując NSObject*, choć. Zwykle jest konflikt między dwoma bardziej konkretnych klas.)

+2

Świetne wyjaśnienie, choć wahałem się powiedzieć, że "Ogólnie rzecz biorąc, id jest tym, czego chcesz". Chociaż "id" jest dość elastyczny ze względu na dynamiczne pisanie, nie zapewnia praktycznie żadnych ostrzeżeń, więc jeśli wywołasz nieobsługiwaną metodę, to, co może zostać przechwycone podczas kompilacji, staje się problemem w czasie wykonywania. Pisanie statyczne (za pomocą MyClassName * itp.), gdy jest używane rozważnie, może znacznie uprościć życie, szczególnie podczas debugowania w Xcode (może pokazać bardziej inteligentne podsumowanie obiektu) lub wywołania metody catch z błędnie lub niekompletnymi selektorami. –

+0

Rozróżnienie, które zamierzałem narysować, to między konkretnie id i NSObject *, a nie ogólnie typowanie statyczne. Znacznie częściej używamy identyfikatora niż statycznego typu jako NSObject. – Chuck

+0

@simpleBob: Stąd "jakakolwiek znana wiadomość". – Chuck

17

id oznacza „obiekt”, NSObject * oznacza „instancję NSObject lub jednej z jej podklas”. Istnieją obiekty w Objective-C, które nie są NSObject s (te, które spotkasz w Cocoa w tej chwili są NSProxy,i Class). Jeśli jakiś kod oczekuje obiektu danej klasy, deklarując, że pomaga kompilatorowi sprawdzić, czy używasz go poprawnie. Jeśli naprawdę możesz wziąć "dowolny obiekt" - na przykład deklarujesz delegata i przetestujesz wszystkie metody wysyłania z rozmowami respondsToSelector: - możesz użyć numeru .

Innym sposobem zadeklarować zmienną przedmiot jest jak „id <NSObject>”, co oznacza „każdy obiekt, który realizuje NSObject protokół.

+0

NSProxy i Protocol to klasy. "Klasa" nie jest klasą, ale po prostu typem, który może odnosić się do wskaźników do obiektów klasy. Nie grupuj ich razem. – user102008

+0

@ user102008: możesz wysyłać wiadomości do klasy, co czyni je obiektem w świecie objc. –

+0

tak, obiekty klasy są obiektami, ale nie należą do klasy o nazwie "Klasa" – user102008

10

Z moją ograniczoną zrozumienia celu C nie wszystkie obiekty pochodzą z NSObject (w przeciwieństwie Java, gdzie wszystkie obiekty pochodzą z Object) Teoretycznie możesz mieć inne obiekty root ID może mieć zastosowanie do dowolnych obiektów pochodnych nie pochodzących z NSObject

0

Chciałbym dodać kolejną różnicę. Gdy dodajesz protokół do id, nie oznacza to już, że będzie to typ NSObject *, to po prostu oznacza, że ​​będzie to jakikolwiek clas s to potwierdza ten protokół.

Tak więc, na przykład, ten kod nie będzie rzucać żadnego błędu, ponieważ NSObject „s kategoria NSDelayedPerforming ma tę metodę:

id testId; 
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5]; 

Jednak ten kod pokaże błąd No known instance method for selector "performSelector:withObject:afterDelay:":

id<NSMutableCopying> testId; 
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5]; 
Powiązane problemy