wake-up-neo.com

Gibt es so etwas wie eine generische Liste in Cocoa/Objective-C?

Was mir in C # am besten gefällt, sind generische Listen. Eine Liste, die nur einen Objekttyp enthalten kann. Gibt es so etwas wie eine generische Liste in Cocoa/Objective-C? Bisher kenne ich nur NSArray, die einen Zeiger auf ein Objekt nehmen.

30
TalkingCode

Dies in einer Cocoa-App zu wollen, ist oft ein Zeichen für ein schwaches Design.

NSArray ist unveränderlich, daher "nimmt sie keinen Zeiger auf ein Objekt" und enthält vermutlich bereits die richtigen Objekte, wenn sie Ihnen übergeben werden. Ich nehme an, Sie machen sich mehr Sorgen über eine NSMutableArray, in der Sie der Meinung sind, dass andere Teile Ihres Codes möglicherweise die falsche Art von Objekt hinzufügen. Aber schau dir Cocoa selbst an. Es ist unglaublich selten, ein veränderbares Array als Teil eines Klassenentwurfs verfügbar zu machen.

Stattdessen legen Sie im Allgemeinen eine NSArray und einige Methoden zum Ändern dieses Arrays offen. Etwas in der Art von:

@class Foo : NSObject
- (NSArray *)bars;
- (void)addBar:(Bar *)bar;
- (void)removeBar:(Bar *)bar;
@end

Dies verhindert normalerweise, dass falsche Objekte einfach durch eine Compiler-Warnung eingefügt werden. Wenn Sie möchten, können Sie natürlich auch Assertions in -addBar: und -removeBar: hinzufügen.

34
Mike Abdullah

Objective-C unterstützt keine generische Programmierung. Sie können immer Objective-C++ und eine STL-Liste verwenden.

9
Ferruccio

Generische NSArrays können durch Unterklassen von NSArray und Neudefinieren aller bereitgestellten Methoden mit restriktiveren Methoden realisiert werden. Zum Beispiel, 

- (id)objectAtIndex:(NSUInteger)index

müsste in neu definiert werden

@interface NSStringArray : NSArray

wie

- (NSString *)objectAtIndex:(NSUInteger)index

damit ein NSArray nur NSStrings enthält.

Die erstellte Unterklasse kann als Drop-In-Ersetzung verwendet werden und bietet viele nützliche Funktionen: Compiler-Warnungen, Zugriff auf Eigenschaften, bessere Code-Erstellung und -Erfüllung in Xcode. Bei all diesen Funktionen handelt es sich um Funktionen zur Kompilierungszeit. Die tatsächliche Implementierung muss nicht neu definiert werden. Die Methoden von NSArray können weiterhin verwendet werden.

Es ist möglich, dies zu automatisieren und auf nur zwei Anweisungen zu reduzieren, wodurch es sich an Sprachen heranleitet, die Generika unterstützen. Ich habe eine Automatisierung mit WMGenericCollection erstellt, bei der Vorlagen als C-Preprozessor-Makros bereitgestellt werden.

Nach dem Importieren der Header-Datei, die das Makro enthält, können Sie ein generisches NSArray mit zwei Anweisungen erstellen: eine für die Schnittstelle und eine für die Implementierung. Sie müssen nur den Datentyp angeben, den Sie speichern möchten, und Namen für Ihre Unterklassen. WMGenericCollection stellt solche Vorlagen für NSArray, NSDictionary und NSSet sowie deren veränderlichen Gegenstücke bereit.

3
w-m

Nein, Objective-C unterstützt derzeit keine parametrische Typisierung für Collection-Elemente.

Dieses Thema ist jedoch komplexer als die Frage oder die vorhandenen Antworten zugeben.

Parametrische Typisierung für Sammlungen in Objective-C ist nicht identisch mit Generics in C #/Java. Es ist zum Beispiel unwahrscheinlich, dass Objective-C jemals die Möglichkeit bietet, jedes Objekt, das einer Collection hinzugefügt wird, zu gewährleisten, dassein NSArray-Typ oder -Untertyp ist. Stattdessen könnte Objective-C (und IMO sollte) die Möglichkeit haben, jedes Objekt in einer Sammlung sicherzustellenENTSPRICHTeinem Protokoll/einer Schnittstelle. (d. h. dass eine Reihe erforderlicher Methoden implementiert wird)

Warum?

Objective-C ist eine Sprache, die auf der Kompatibilität mit Protokollen (Schnittstellen) basiert und NICHT mit Subtyping-Beziehungen. Das heißt, Objekte sind kompatibel, wenn sie über die richtigen Methoden verfügen und wir uns nicht um ihre tatsächlichen Typen kümmern. In der Tat ist das Betrachten der tatsächlichen Typen eine sehr schlechte Praxis in Obj-C und in sehr entmutigter Weise. Dieser Begriff wird manchmal als "Duck Typing" bezeichnet, denn wenn er wie eine Ente quitscht, ist es eine Ente. Es ist uns egal, ob es buchstäblich von einer bestimmten Ente geerbt wurde oder nicht. Dies verhindert, dass Sie von einer anderen Implementierungshierarchie aufgesattelt werden. - Das Ergebnis ist, dass, solange ein Objekt, das aus der Liste kommt, eine draw :: -Methode hat, es funktioniert, es uns egal ist, ob es sich um eine Unterklasse eines bestimmten JimmyDrawableBase-Objekts handelt. 

Dadurch wird Code nicht nur wiederverwendbar, sondern auch eine etwas andere (funktionalere?) Art der Problemzerlegung, da Sie sich nicht darauf verlassen können, dass Objekte von einer bestimmten Basisklasse abgeleitet werden und somit eine Menge Ihrer Basisklasse enthält Umsetzung in sie gezwungen.

Ich persönlich denke, es wäre Nice für den Obj-C-Compiler, um eine parametrische Überprüfung desPROTOKOLLS* CONFORMANCE * durchzuführen. Das heißt, um ein NSMutableArray herzustellen, das erfordert, dass alle darin platzierten Objekte einem gegebenen Protokoll entsprechen (d. H. Einen bestimmten Satz erforderlicher Methoden haben). 

Manchmal widersetzt sich auch die flexiblere Protokoll-Konformitätsprüfung dynamischen Programmierern und aus guten Gründen. Programmierer haben oft eine Möglichkeit, die Konformitätsanforderungen zu übermäßig zu spezifizieren. 

Beispielsweise könnte es erforderlich sein, dass eine Liste Objekte enthält, die mit dem NSArray-Protokoll/der -Schnittstelle übereinstimmen. Sie könnten jedochEIGENTLICHnur zwei dieser Methoden aufrufen. Dies ist eine Überkonformität. Jemand, der ein kompatibles Element in Ihr Array aufnehmen möchte, muss eine Vielzahl von Methoden implementieren, die Sie nicht tatsächlich aufrufen - zumindest noch nicht (siehe nächste Seite).

Google Go versucht, dieses Problem zu lösen, indem strukturelle Kompatibilität abgeleitet wird. Wenn Sie also draw () für Elemente aufrufen, die aus einer Liste stammen, stellt der Compiler sicher, dass alles, was in eine Liste geht, eine draw () -Methode enthält. Wenn es keine draw () -Methode enthält, ist es ein Compiler-Fehler, wenn Sie es in die Liste aufnehmen. Dadurch wird verhindert, dass der Code einfach zur Laufzeit den gleichen Fehler verursacht. Das Problem dabei ist, dass es nur für die Kompilierung ganzer Programme funktioniert. Wenn Google-Go modulare DLLs kompilieren könnte (was nicht möglich ist), würde dies zu dem Problem führen, dass es für mich keine Möglichkeit gibt zu sagen, dass Objekte in der Liste eine bestimmte Schnittstelle mit drei Methoden unterstützen müssen, obwohl dies möglich ist Ich rufe sie heute nicht an, weil ich sie in Zukunft nennen könnte

Zwischen diesen beiden Lösungen gefällt der Kompromiss und die Wahrheit.

Ich persönlich würde es mir wünschen, wenn Objective-C die parametrische Protokollkonformität hinzufügt, und ich könnte den Compiler bitten, sicherzustellen, dass der Inhalt einer bestimmten Sammlung immer mit einem bestimmten Satz von Protokollen übereinstimmt. 

Ich möchte auch, dass der Compiler mir hilft, Überkonformität zu vermeiden. Wenn ich in diesen Protokollen keine Methoden für Objekte aufrufe, sollte dies zu Fehlermeldungen/Warnungen führen. Wenn ich sie im Protokoll behalten möchte, obwohl ich sie nicht verwende, sollte ich explizit für jede Methode im Protokoll eine Erklärung abgeben, dass sie "in der Zukunft verwendet werden kann", sodass alle Elemente sie jetzt bereitstellen müssen ". Dies bedeutet zumindest, dass der Prozess der Überkonformität MEHR Arbeit erfordert, statt Java/C #, wo weniger Arbeit erforderlich ist.

0
David Jeske