Objective-c Internal für NSArray und NSMutableArray

8

Sehr interessante Frage für alle die in Objective-c Interna ...

Also ... das NSObject liefert die gleiche Implementierung von copy für beide und ein Objekt und eine Klasse (wie ich es erwarte). % Co_de% und NSArray geben jedoch nicht nur verschiedene Implementierungen von NSMutableArray für ein Objekt und eine Klasse zurück, sondern jedes Objekt hat eine andere Implementierung.

Weiß jemand, warum der folgende Code ein solches Verhalten erzeugt? ... (Zumindest die Klassenimplementierungen für objectAtIndex: und NSArray sind gleich :))

%Vor%

Das Protokoll

%Vor%     
Eamonn Moloney 06.11.2012, 16:46
quelle

1 Antwort

26

Implementierungsdetails, alle davon. Dies ist also ein relativ gut informiertes Vermutungsbeispiel.

Erstens müssen Sie nicht durch solche Ringe springen, um einen Hexadezimalwert zu drucken, tun Sie einfach:

%Vor%

Beachten Sie, dass das Aufrufen von methodForSelector: für ein Klassenobjekt das IMP für eine Klassenmethode zurückgibt.

Nun zu der nächsten Frage.

Eine Sache, die Objective-C von anderen populären OO-Sprachen (aber nicht allen) unterscheidet, ist, dass Klassenobjekte tatsächlich Instanzen einer Metaklasse sind. Diese Metaklasse - die eigentlich keinen Namen jenseits von "Metaklasse" hat - antwortet (mehr oder weniger) auf das NSObject -Protokoll. Tatsächlich ist es irgendwie eine Ableitung von NSObject .

Wenn Sie also die Implementierung für bestimmte Selektoren in NSObject für Instanzen und Klassen erhalten, sind sie oft identisch. Beachten Sie, dass dies eine Klasse zu einem Schlüssel in einem NSDictionary macht. Klassen können kopiert werden. NSObject 's copy Methode tut nur return [self retain]; und, natürlich, retain für eine Klasse ist ein No-Op, da sie [fast immer] statisch in die Binärdatei als Singletons kompiliert werden. Nun, technisch gesehen ruft copy copyWithZone: auf, was return [self retain]; tut (deshalb müssen Sie copyWithZone: ableiten, obwohl Zonen veraltet sind).

Nun, wie Hot Licks darauf hingewiesen hat, ist NS*Array ein Klassencluster, dessen interne Implementierungsdetails sich in den letzten Releases geändert haben. Es war einmal so, dass alle Instanzen zu NSCFArray überbrückt wurden, das anders konfiguriert war. In neueren Releases sehen Sie (sic.)% Co_de% und __NSArrayI Instanzen, die unveränderlichen und veränderbaren Instanzen entsprechen. Meistens - da ist mehr los als nur das, aber das ist ziemlich typisch.

Dass die Instanzmethoden für __NSArrayM zwischen den beiden Klassen unterschiedlich sind, ist typisch für Klassencluster. Der Punkt eines Clusters ist die Bereitstellung einer primitiven Schnittstelle mit einer Reihe von Methoden, die in Bezug auf diese primitive Schnittstelle implementiert sind (weshalb die Header zwischen dem Kern objectAtIndex: und einer Reihe kategorischer @interface aufgeteilt sind; die Kategorien in der Basisklassen werden vollständig in Bezug auf die Kern-API implementiert).

Intern gibt es konkrete Unterklassen der öffentlich deklarierten Klassen innerhalb des Clusters. Diese konkreten Unterklassen sind in hohem Maße für eine bestimmte Aufgabe optimiert - in diesem Fall unveränderlicher vs. veränderbarer Array-Speicher (aber es gibt möglicherweise viel mehr nicht-öffentliche Unterklassen, die für unterschiedliche Zwecke optimiert sind), wo die abgeleiteten Klassen die beworbene API überschreiben optimierte Versionen der verschiedenen Methoden.

Was Sie also in den beiden Klassen sehen, sind verschiedene Implementierungen von @interfaces , die für den veränderlichen und den unveränderlichen Fall optimiert sind.

Nun, warum sind die Klassenmethoden gleich? Gute Frage. Versuchen wir es zu nennen:

%Vor%

Aha! Sie fragen also nach der Implementierung einer Methode, die beim Aufruf eine "Diese Methode nicht erkennen" -Ausnahme aufruft. Tatsächlich:

%Vor%

Es sieht so aus, als ob die Laufzeitumgebung einen IMP zurückgibt, der einen schönen Fehler anzeigt, der anzeigt, dass Sie versucht haben, einen Selektor zu verwenden, durch den das Zielobjekt (in diesem Fall eine Metaklasseninstanz) nicht reagiert zu. Deshalb gibt die Dokumentation für objectAtIndex: an, dass Sie instanceMethodForSelector: prior in Fällen verwenden sollten, in denen es eine Frage darüber gibt, ob das Ziel den Selektor implementiert.

(Nun, das wurde mehr zu einem Buch als beabsichtigt ... hoffentlich immer noch nützlich!)

    
bbum 06.11.2012, 17:27
quelle

Tags und Links