2010-06-24 14 views
44

In Objective-C, können Sie Klassenmethoden mit aufrufen:Warum müssen wir in Objective-C [MyClass-Klasse] machen?

[MyClass aClassMethod]; 

Und Sie können mit einer Instanz der Art abfragen:

[someInstance isKindOfClass:[MyClass class]]; 

Aber warum müssen wir [MyClass class], und nicht einfach zu tun, bieten MyClass wie folgt aus:

[someInstance isKindOfClass:MyClass]; 

gibt es einen Grund, dass der Compiler in Ordnung ist MyClass mit der Begegnung als Empfänger (ein Zeigertyp) aber nicht als Argument? Ist es eine Einschränkung beim Parsen der Sprache? Oder vielleicht eine Einschränkung des Compilers?

+8

+1 interessante Frage! Ich hätte nie darüber nachgedacht (zumindest nicht auf diese Weise) –

Antwort

41

Ooooh ... Spaß Frage. Die Antwort ist ein c-ism.

Bedenken Sie:

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

Nun sagen Sie:

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

In diesem Zusammenhang hat der Compiler MyClass als Typdefinition sieht. Die * besagt, dass die Variable m eine pointer to a hunk o' memory that contains one (or many -- don't forget your C pointer-fu) MyClass instances ist.

Mit anderen Worten, MyClass ist ein Typ.

Aber im Zusammenhang mit so etwas wie:

[someInstance isKindOfClass: x ]; 

x muss ein R-Wert oder, in menschlicher Hinsicht sein, der Wert eines Ausdrucks. Ein Typ kann jedoch nicht als R-Wert verwendet werden.

Das funktioniert [MyClass class] ist eigentlich ein bisschen ein Hack, sowohl in der Sprache und dem Compiler, in dem die Grammatik ausdrücklich erlaubt, dass ein Typ-Name der Nachrichtenempfänger (das Ziel eines Methodenaufrufs sein).

Und, wie in der Tat, können Sie tun:

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

Es wird alle Arbeit. Sie können jedoch die folgenden nicht tun, aber die Fehlermeldung Beleuchtung:

[NSUInteger class]; 

Fehler: 'NSUInteger' ist kein Objective-C Klassenname oder Alias ​​


Jetzt , warum nicht Sonderfall überall als bloßer Name?

Das kollidiert Typnamen und rvalues ​​und Sie am Ende müssen schlucken etwas wie [foo isKindOfClass: (MyClass)]; während barfing auf [foo isKindOfClass: (MyClass *)]; die dann auf Typcasting Territorium in einer eher unbequemen Weise eingreift.

+0

Ich wollte gerade einen Kommentar zu meiner Frage schreiben: "Ich frage mich, ob' bbum' eine Antwort hat ... " – dreamlax

+0

@dreamlax @bbum * immer * hat eine Antwort. Er ist einfach so großartig. :) –

+0

Hoppla, 's/Wunder, wenn/wissen, dass /' und 's/an/the' – dreamlax

-1

Denn was die isKindOfClass erwartet eine „Klasse“ und das ist, was von dem Aufruf zurück erhalten: [MyClass class]

+0

Aber warum ist 'MyClass' selbst keine Klasse, wenn es bereits ein gültiger Empfänger ist? – dreamlax

+0

weil 'MyClass' ist-ein' NSObject' (am wahrscheinlichsten), da es 'NSObject' und nicht eine' Klasse' erbt: http://developer.apple.com/mac/library/documentation/cocoa/reference/foundation /Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/isKindOfClass: – OscarRyz

+1

Dann rufen '[[MyClass class] someMethod]' und '[MyClass someMethod]' jeweils die gleiche Methode auf? – dreamlax

1

Meine erste Blick Antwort ist, weil [MyClass Klasse], um ein Objekt vom Typ Klasse zurück und MyClass nicht erben aus der Klasse ...

+2

Wenn dies der Fall wäre, wäre es ein Typenkonfliktfehler, aber das ist es nicht. Der Compiler scheint 'MyClass' nicht als Ausdruck zu behandeln. – dreamlax

+4

Betrachte: 'id f1 = [NSFileManager defaultManager]; id f2 = [[NSFileManager-Klasse] defaultManager]; 'Dies würde bedeuten, dass' [NSFileManager-Klasse] == NSFileManager' (und ja, 'f1 == f2') –

+2

John,' Class' ist ein [Datentyp ] (http://developer.apple.com/mac/library/documentation/cocoa/reference/objcruntimeref/Reference/reference.html#//apple_ref/doc/uid/TP40001418-CH3g-objc_class), das von Objective-C verwendet wird Laufzeit, keine Objective-C-Klasse. –

-2

MyClass ist nicht vom Typ Class.

[MyClass class] ist vom Typ Class.

Wenn Sie mit Java vertraut sind, ist das Konzept das gleiche.

java.lang.String ist nicht vom Typ java.lang.Class

java.lang.String.getClass() vom Typ java.lang.Class

+3

"MyClass ist nicht vom Typ Klasse" => Warum können Sie '[MyClass myClassMethod]' und auch '[[MyClass class] myClassMethod]' verwenden und die gleiche Funktionalität erhalten? –

7

Interessant.

In Objective-C hat Klassenname zwei Rollen, als Datentyp und als Klassenobjekt. Als Datentypnamen, können Sie tun Dinge wie: nur als Nachrichtenempfänger

MyClass *anObject; 

als Klassenobjekt kann der Klassenname für das Klassenobjekt stehen. Und das ist, warum Sie

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

jedoch verwenden, ich glaube nicht, das ist die Antwort, die Ihren Bedarf befriedigen zu können. Für mich lautet die Antwort: "Ja, was du willst, ist plausibel. Aber die Spezifikation sagt den anderen Weg".

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

+3

Dies ist im Grunde eine C-Kompatibilität. Die Empfängerposition ist speziell ausgelegt, um Klassennamen zuzulassen, aber überall sonst wird sie als normaler C-Typ behandelt. – Chuck

+1

Und @Chuck bekommt den Preis! Du solltest das als Antwort einreichen, Chuck. Das ist der wahre Grund. –

-1

Ich denke, dass MyClass eigentlich eine Meta-Klasse ist. Sie senden ihm die Klassennachricht, um die tatsächliche Klasse (vom Typ Klasse) zu erhalten.

+0

Nein, du kannst nicht. Das liegt daran, dass es auch eine '+ class'-Klassenmethode gibt, die die von Ihnen angesprochene' -class'-Instanzmethode außer Kraft setzt. Sie * können * die Klasse mit der Laufzeitfunktion 'object_getClass()' erhalten, und Sie erhalten ihre Meta-Klasse. Es gibt keine Klasse namens "Klasse". ("Klasse" ist nur ein generischer Typ für Zeiger auf Klassenobjekte) – user102008

2

@John und @ryanprayogo - Sie sind beide grundlegend falsch. MyClass ist eine Klasse, die auch ein Objekt ist, aber nicht von NSObject erbt. Objective-C ist auf diese Weise irgendwie komisch, aber es ist wirklich brillant, wenn es vollständig erklärt wird (siehe here). Die Antwort hier ist jedoch, wie @ Yehnan sagte, dass ein Klassenname entweder ein Typname für Deklaratoren und Umwandlungen sein kann, oder als ein Empfänger für Nachrichten. Die Implementierung von [MyClass class] gibt self zurück (was innerhalb der Methode MyClass ist).Auch wie @ Yehnan sagte, könnte die Sprache unterstützen es als Argument übergeben, obwohl es einfach nicht.

+0

"Erbt aber nicht von NSObject" Nein, er erbt schließlich NSObject, wenn NSObject die Stammklasse von MyClass ist. – user102008

1

@ Yehnan fängt es gut ein, aber ich werde ein wenig darauf erweitern. Ja, der Compiler könnte so modifiziert werden, dass er automatisch eine Klassenkennung in die entsprechende Class an Stellen umwandelt, an denen es ein Argument ist, und nicht nur dann, wenn es das Ziel einer Nachricht ist. Aber es gibt keine große Nachfrage nach dieser zusätzlichen Komplexität im Compiler (übersetzt: langsamere, schwerer zu erkennende Codierungsfehler). Du solltest Dinge, die oft Class zurückgeben, nicht aufrufen. Wenn dies der Fall ist, ist das Objektmodell fehlerhaft. Klassenprüfung sollte der letzte, verzweifelte Ansatz sein, nachdem alles andere fehlgeschlagen ist (vor allem korrekte Eingabe und dann respondsToSelector:). Für diese Art von seltenen Ereignissen ist es nicht sinnvoll, den Compiler auf diese Weise zu komplizieren.

+0

Was wäre, wenn Sie eine Laufzeitumgebung implementieren würden? – dreamlax

+0

Welche Art von Laufzeit? Wenn es auf der Laufzeit von ObjC basiert, dann arbeiten Sie meistens in C-Aufrufen wie class_getClassMethod(). Und eine Laufzeit würde immer noch hauptsächlich an Klassenvariablen interessiert sein, nicht an hartcodierten Klassenbezeichnern. Worauf bauen Sie, dass Sie häufig Klassenkennungen fest codieren müssen? –

+0

Ich habe über eine alternative Objective-C-Laufzeit gesprochen, aber ich baue nichts, ich bin nur neugierig zu erfahren, wie der Parser 'MyClass' in verschiedenen Kontexten interpretiert. – dreamlax

Verwandte Themen