wake-up-neo.com

Gibt es in Objective-C stark typisierte Sammlungen?

Ich bin neu in der Mac/iPhone-Programmierung und in Objective-C. In C # und Java) haben wir "generics", Auflistungsklassen, deren Mitglieder nur vom deklarierten Typ sein können. Zum Beispiel in C #

Dictionary<int, MyCustomObject>

kann nur Schlüssel enthalten, die Ganzzahlen und Werte vom Typ MyCustomObject sind. Gibt es einen ähnlichen Mechanismus in Objective-C?

138
Rich

In Xcode 7 hat Apple 'Lightweight Generics' in Objective-C eingeführt. In Objective-C werden Compiler-Warnungen generiert, wenn eine Typinkongruenz vorliegt.

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

Und im Code Swift erzeugen sie einen Compiler-Fehler:

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

Lightweight-Generika sind für die Verwendung mit NSArray, NSDictionary und NSSet vorgesehen. Sie können sie jedoch auch Ihren eigenen Klassen hinzufügen:

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

Objective-C verhält sich wie zuvor bei Compiler-Warnungen.

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

aber Swift ignoriert die allgemeinen Informationen vollständig. (Nicht mehr wahr in Swift 3+.)

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

Abgesehen von diesen Foundation-Sammlungsklassen werden Objective-C-Lightweight-Generika von Swift ignoriert. Alle anderen Typen, die Lightweight-Generika verwenden, werden in Swift) importiert, als wären sie nicht parametrisiert.

Interaktion mit Objective-C-APIs

209
Connor

Diese Antwort ist veraltet, bleibt aber für den historischen Wert. Ab Xcode 7 ist die Antwort von Connor vom 8. Juni 15 genauer.


Nein, in Objective-C gibt es keine Generika, es sei denn, Sie möchten C++ - Vorlagen in Ihren eigenen benutzerdefinierten Auflistungsklassen verwenden (von denen ich dringend abraten möchte).

Objective-C verfügt über eine dynamische Typisierung. Dies bedeutet, dass sich die Laufzeit nicht um den Typ eines Objekts kümmert, da alle Objekte Nachrichten empfangen können. Wenn Sie ein Objekt zu einer integrierten Auflistung hinzufügen, werden sie so behandelt, als wären sie vom Typ id. Aber keine Sorge, senden Sie einfach wie gewohnt Nachrichten an diese Objekte. es wird gut funktionieren es sei denn natürlich, eines oder mehrere der Objekte in der Sammlung antworten nicht auf die Nachricht, die Sie senden.

Generika werden in Sprachen wie Java und C # benötigt, da es sich um starke, statisch typisierte Sprachen handelt. Völlig anderes Ballgame als die dynamische Typisierungsfunktion von Objective-C.

91
Marc W

Nein, aber um es klarer zu machen, können Sie es mit der Art des Objekts kommentieren, das Sie speichern möchten. Ich habe dies einige Male gesehen, als Sie etwas in Java 1.4 heutzutage) schreiben müssen. z.B:

NSMutableArray* /*<TypeA>*/ arrayName = ....

oder

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
11
Mark Rhodes

In Objective-C gibt es keine Generika.

Aus den Dokumenten

Arrays sind geordnete Sammlungen von Objekten. Cocoa bietet verschiedene Array-Klassen, NSArray, NSMutableArray (eine Unterklasse von NSArray) und NSPointerArray.

6
Matthew Vines

Apple hat ObjC in XCode 7 um Generika erweitert:

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

siehe hier: https://developer.Apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//Apple_ref/doc/uid/TP40014216-CH6-ID61 =

6
user1259710

Dies wurde in Xcode 7 veröffentlicht (endlich!)

Beachten Sie, dass es sich bei Objective C-Code nur um eine Prüfung zur Kompilierungszeit handelt. Es tritt kein Laufzeitfehler auf, wenn nur der falsche Typ in eine Auflistung eingefügt oder einer typisierten Eigenschaft zugewiesen wird.

Erklären:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

Verwenden:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

Sei vorsichtig mit diesen *s.

5
Kevin

Generische NSArrays können durch Unterklassen von NSArray und Neudefinition aller bereitgestellten Methoden mit restriktiveren Methoden realisiert werden. Beispielsweise,

- (id)objectAtIndex:(NSUInteger)index

müsste in neu definiert werden

@interface NSStringArray : NSArray

wie

- (NSString *)objectAtIndex:(NSUInteger)index

ein NSArray darf nur NSStrings enthalten.

Die erstellte Unterklasse kann als Drop-In-Ersatz verwendet werden und bietet viele nützliche Funktionen: Compiler-Warnungen, Eigenschaftenzugriff, bessere Codeerstellung und -vervollständigung in Xcode. All dies sind Features zur Kompilierungszeit. Es ist nicht erforderlich, die tatsächliche Implementierung neu zu definieren. Die Methoden von NSArray können weiterhin verwendet werden.

Es ist möglich, dies zu automatisieren und es auf nur zwei Anweisungen zu reduzieren, wodurch es Sprachen nahe kommt, die Generika unterstützen. Ich habe eine Automatisierung mit WMGenericCollection erstellt, wobei Vorlagen als C-Präprozessor-Makros bereitgestellt werden.

Nach dem Import der Header-Datei mit dem Makro 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 zu speichernden Datentyp und die Namen für Ihre Unterklassen angeben. WMGenericCollection stellt solche Vorlagen für NSArray, NSDictionary und NSSet sowie ihre veränderlichen Gegenstücke bereit.

Ein Beispiel: List<int> könnte durch eine benutzerdefinierte Klasse namens NumberArray realisiert werden, die mit der folgenden Anweisung erstellt wird:

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

Sobald Sie NumberArray erstellt haben, können Sie es überall in Ihrem Projekt verwenden. Es fehlt die Syntax von <int>, aber Sie können Ihr eigenes Benennungsschema wählen, um diese als Klassen als Vorlagen zu kennzeichnen.

4
w-m

Jetzt werden Träume wahr - es gibt Generika in Objective-C seit heute (danke, WWDC). Es ist kein Scherz - auf offizielle Seite von Swift:

Mit den neuen Syntaxfunktionen können Sie aussagekräftigeren Code schreiben und gleichzeitig die sprachübergreifende Konsistenz verbessern. Die SDKs haben neue Objective-C-Funktionen wie Generika und Annotations für die Nichtigkeit verwendet, um Swift Code noch sauberer und sicherer zu machen. Hier ist nur eine Auswahl von Swift 2.0-Verbesserungen.

Und ein Bild, das das beweist:Objective-C generics

2
htzfun

Schauen Sie sich an:

https://github.com/tomersh/Objective-C-Generics

Es scheint eine Art von Generika für arme Leute zu sein, indem der Mechanismus zur Protokollprüfung neu verwendet wird.

2
David Jeske

Ich will nur hier rein springen. Ich habe einen Blog-Beitrag geschrieben hier über Generika.

Ich möchte dazu beitragen, dass Generics zu jeder Klasse hinzugefügt werden können , nicht nur zu den Auflistungsklassen wie Apple zeigt an.

Ich habe dann erfolgreich eine Vielzahl von Klassen hinzugefügt, da sie genauso funktionieren wie Apples Sammlungen. dh Überprüfung der Kompilierungszeit, Vervollständigung des Codes, Entfernen von Casts usw.

Genießen.

2
drekka