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?
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.
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.
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 = ...
In Objective-C gibt es keine Generika.
Arrays sind geordnete Sammlungen von Objekten. Cocoa bietet verschiedene Array-Klassen, NSArray, NSMutableArray (eine Unterklasse von NSArray) und NSPointerArray.
Apple hat ObjC in XCode 7 um Generika erweitert:
@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;
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.
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.
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:
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.
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.