2010-06-24 7 views
44

In Objective-C, è possibile richiamare i metodi di classe con:Perché dobbiamo fare [classe MyClass] in Objective-C?

[MyClass aClassMethod]; 

e si può interrogare tipo di un'istanza con:

[someInstance isKindOfClass:[MyClass class]]; 

Ma, perché abbiamo bisogno di fare [MyClass class], e non semplicemente fornire MyClass come questo:

[someInstance isKindOfClass:MyClass]; 

c'è una ragione che il compilatore va bene incontrare MyClass come ricevitore (un tipo di puntatore) ma non come argomento? È una limitazione dell'analisi della lingua? O forse una limitazione del compilatore?

+8

+1 domanda interessante! Non ci avevo mai pensato prima (almeno non in questo modo) –

risposta

41

Ooooh ... domanda divertente. La risposta è un c-ismo.

considerare:

@interface MyClass : NSObject 
@end 
@implementation MyClass 
@end 

Ora, supponiamo di avere:

... 
MyClass *m = nil; 
... 

In tale contesto, il compilatore vede MyClass come una definizione di tipo. Il * dice che la variabile m è un pointer to a hunk o' memory that contains one (or many -- don't forget your C pointer-fu) MyClass instances.

In altre parole, MyClass è un tipo.

Ma, nel contesto di qualcosa come:

[someInstance isKindOfClass: x ]; 

x deve essere un rvalue o, in termini umani, il valore di un'espressione. Un tipo, tuttavia, non può essere utilizzato come valore.

Questo [MyClass class] funziona in realtà è un po 'un hack, sia nella lingua che nel compilatore, in quanto la grammatica consente specificamente a un nome di tipo di essere il destinatario del messaggio (per essere l'obiettivo di una chiamata di metodo).

E, come un dato di fatto, si può fare:

typedef MyClass Foo; 
.... 
[MyClass class]; 
[Foo Class]; 

sarà tutto il lavoro. Tuttavia, non è possibile effettuare le seguenti operazioni ma il messaggio di errore è illuminante:

[NSUInteger class]; 

errore: 'NSUInteger' non è un nome di classe Objective-C o alias


Ora , perché non caso speciale dappertutto come un nome spoglio?

Questo collude nomi di tipi e valori e si finisce rapidamente per dover inghiottire qualcosa come [foo isKindOfClass: (MyClass)]; mentre il barattolo su [foo isKindOfClass: (MyClass *)]; che poi invade il territorio di typecasting in modo piuttosto scomodo.

+0

Avevo appena postato un commento sulla mia domanda dicendo "Mi chiedo se' bbum' abbia una risposta ... " – dreamlax

+0

@dreamlax @bbum * always * ha una risposta. È semplicemente fantastico. :) –

+0

Oops, 's/chiedo se/so che /' e 's/an/the' – dreamlax

-1

Perché quello che i isKindOfClass si aspetta è una "classe", e questo è ciò che ottenere tornato da invocare: [MyClass class]

+0

Ma perché 'MyClass' da solo non è una classe, se è già un ricevitore valido? – dreamlax

+0

perché 'MyClass' è-un' NSObject' (molto probabilmente) poiché eredita 'NSObject' e non un' Class' vedere: http://developer.apple.com/mac/library/documentation/cocoa/reference/foundation /Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/isKindOfClass: – OscarRyz

+1

Quindi, come '[[MyClass class] someMethod]' e '[MyClass someMethod]' ognuno invoca lo stesso metodo? – dreamlax

1

La mia prima risposta sguardo è perché [MyClass classe] restituisce un oggetto di tipo Class, e MyClass non eredita dalla classe ...

+2

Se questo fosse il caso, sarebbe un errore di mancata corrispondenza di tipo, ma non lo è. Sembra che il compilatore non consideri 'MyClass' come un'espressione. – dreamlax

+4

Considera: 'id f1 = [NSFileManager defaultManager]; id f2 = [[NSFileManager class] defaultManager]; 'Questo sembrerebbe indicare che' [NSFileManager class] == NSFileManager' (e sì, 'f1 == f2') –

+2

John,' Class' è un [tipo di dati ] (http://developer.apple.com/mac/library/documentation/cocoa/reference/objcruntimeref/Reference/reference.html#//apple_ref/doc/uid/TP40001418-CH3g-objc_class) utilizzato dall'Obiettivo-C runtime, non una classe Objective-C. –

-2

MyClass non è di tipo Class.

[MyClass class] è di tipo Class.

Se si ha familiarità con Java, il concetto è lo stesso.

java.lang.String non è di tipo java.lang.Class

java.lang.String.getClass() è di tipo java.lang.Class

+3

"MyClass non è di tipo Class" => Allora perché puoi fare '[MyClass MyClassMethod]' e anche '[[MyClass class] myClassMethod]' e ottenere la stessa funzionalità? –

7

interessante.

In Objective-C, il nome classe ha due ruoli, come un tipo di dati e un oggetto di classe. Come un nome del tipo di dati, è possibile fare cose come:

MyClass *anObject; 

come un oggetto di classe, il nome della classe può stare per l'oggetto di classe solo come destinatario del messaggio. E questo è il motivo per cui è necessario utilizzare

... isKindOfClass:[MyClass class] ... 

Tuttavia, non credo che questa è la risposta che può soddisfare il vostro bisogno. Per me, la risposta è "sì, quello che vuoi è plausibile, ma le specifiche dicono l'altro modo".

Riferimento: The Objective-C Programming Language Page 32, section: "Class Names in Source Code".

+3

Questo è fondamentalmente un problema di compatibilità C. La posizione del ricevitore è di tipo speciale per consentire nomi di classi, ma in qualsiasi altro caso viene considerata come un normale tipo C. – Chuck

+1

E @Chuck ottiene il premio! Dovresti inviarlo come risposta, Chuck. Questa è la vera ragione. –

-1

Sto pensando che MyClass sia in realtà una meta-classe. Si invia il messaggio di classe per ottenere la classe effettiva (di tipo Classe).

+0

No, non puoi. Questo perché esiste anche un metodo di classe '+ class' che sovrascrive il metodo di istanza' -class' di cui si sta parlando. Puoi * ottenere * la classe usando la funzione di runtime 'object_getClass()', e otterrai la sua meta-classe. Non esiste una classe denominata "Classe". ("Classe" è solo un tipo generico per i puntatori agli oggetti classe) – user102008

2

@John e @ryanprayogo - siete fondamentalmente sbagliati. MyClass è una classe, che è anche un oggetto, ma non eredita da NSObject. Objective-C è un po 'strano in questo modo, ma è davvero brillante se completamente spiegato (vedi here). La risposta qui, però, è come ha detto @yehnan, che un nome di classe può essere o un nome di tipo per i dichiaratori e i cast, o come un ricevitore per i messaggi. L'implementazione di [MyClass class] restituisce self (che è, all'interno del metodo, MyClass).Anche come ha detto @yehnan, il linguaggio potrebbe supportare passandolo come argomento, sebbene semplicemente non lo sia.

+0

"ma non eredita da NSObject" No, alla fine eredita da NSObject, se NSObject è la classe radice di MyClass. – user102008

1

@yehnan lo cattura bene, ma mi dilungherò un po 'su questo. Sì, il compilatore può essere modificato per convertire automaticamente un identificatore di classe nel suo applicabile Class in posizioni in cui è un argomento anziché solo quando è il destinatario di un messaggio. Ma non c'è un sacco di richieste per quel tipo di complessità aggiunta nel compilatore (tradotto: più lento, più difficile da rilevare errori di codifica). Non dovresti chiamare cose che restituiscono Class molto spesso. Se lo sei, allora il tuo modello di oggetto è rotto. Il controllo di classe dovrebbe essere l'ultimo, disperato approccio dopo che tutto il resto ha avuto esito negativo (in particolare la tipizzazione corretta e quindi respondsToSelector:). Quindi, per questo tipo di evento raro, non ha molto senso complicare il compilatore in questo modo.

+0

Cosa succede se si sta implementando un runtime? – dreamlax

+0

Che tipo di runtime? Se è costruito sul runtime di ObjC, allora lavoreresti principalmente nelle chiamate C come class_getClassMethod(). E un runtime sarebbe comunque interessato principalmente alle variabili di classe, non analizzando gli identificatori di classe hard-coded. Cosa stai creando che hai bisogno di hardcode identificatori di classe spesso? –

+0

Stavo parlando di creare un runtime Objective-C alternativo, ma non sto costruendo nulla, sono solo curioso di sapere come il parser interpreti 'MyClass' in vari contesti. – dreamlax

Problemi correlati