Update im Jahr 2015
Diese Antwort wurde erstmals Anfang 2011 geschrieben und begann:
Was wir wirklich wollen, ist parametrischer Polymorphismus, damit Sie sagen können NSMutableArray<NSString>
: aber leider ist solche nicht verfügbar.
Im Jahr 2015 hat Apple dies offenbar mit der Einführung von "Lightweight Generics" in Objective-C geändert. Jetzt können Sie Folgendes deklarieren:
NSMutableArray<NSString *> *onlyStrings = [NSMutableArray new];
Aber alles ist nicht ganz so, wie es scheint. Beachten Sie das "Leichtgewicht" ... Dann beachten Sie, dass der Initialisierungsteil der obigen Deklaration keine generische Notation enthält. Während Apple parametrische Sammlungen eingeführt und dem obigen Array eine Nicht-Zeichenfolge direkt hinzugefügt hat onlyStrings
, wie in:
[onlyStrings addObject:@666];
wird die Warnung wie angegeben unzulässig, die Typensicherheit ist kaum hauttief. Betrachten Sie die Methode:
- (void) push:(id)obj onto:(NSMutableArray *)array
{
[array addObject:obj];
}
und das Codefragment in einer anderen Methode derselben Klasse:
NSMutableArray<NSString *> *oops = [NSMutableArray new];
[self push:@"asda" onto:oops];
[self push:@42 onto:oops];
Was Apple implementiert hat, ist im Wesentlichen ein Hinweissystem zur Unterstützung der automatischen Interaktion mit Swift, das eine Art typsicherer Generika aufweist. Auf der Objective-C-Seite ist das System zwar "leichtgewichtig", während der Compiler einige zusätzliche Hinweise liefert, und die Typintegrität liegt letztendlich immer noch beim Programmierer - ebenso wie die Objective-C-Methode.
Also was solltest du verwenden? Die neuen Lightweight- / Pseudo-Generika oder eigene Muster für Ihren Code? Es gibt wirklich keine richtige Antwort. Finden Sie heraus, was in Ihrem Szenario Sinn macht, und verwenden Sie es.
Zum Beispiel: Wenn Sie auf eine Interaktion mit Swift abzielen, sollten Sie die leichten Generika verwenden! Wenn jedoch die Typintegrität einer Sammlung in Ihrem Szenario wichtig ist, können Sie die Lightweight-Generika mit Ihrem eigenen Code auf der Objective-C-Seite kombinieren, wodurch die Typintegrität erzwungen wird, die Swift auf seiner Seite hat.
Der Rest der Antwort von 2011
Als weitere Option finden Sie hier eine kurze allgemeine Unterklasse von NSMutableArray, die Sie mit der Art von Objekt initiieren, die Sie in Ihrem monomorphen Array haben möchten. Mit dieser Option können Sie keine statische Typprüfung durchführen (so viel Sie jemals in Obj-C erhalten haben). Sie erhalten Laufzeitausnahmen beim Einfügen des falschen Typs, genauso wie Sie Laufzeitausnahmen für Index außerhalb der Grenzen usw. erhalten.
Dies wird nicht gründlich getestet und setzt voraus, dass die Dokumentation zum Überschreiben von NSMutableArray korrekt ist ...
@interface MonomorphicArray : NSMutableArray
{
Class elementClass;
NSMutableArray *realArray;
}
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems;
- (id) initWithClass:(Class)element;
@end
Und die Umsetzung:
@implementation MonomorphicArray
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems
{
elementClass = element;
realArray = [NSMutableArray arrayWithCapacity:numItems];
return self;
}
- (id) initWithClass:(Class)element
{
elementClass = element;
realArray = [NSMutableArray new];
return self;
}
- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
if ([anObject isKindOfClass:elementClass])
{
[realArray insertObject:anObject atIndex:index];
}
else
{
NSException* myException = [NSException
exceptionWithName:@"InvalidAddObject"
reason:@"Added object has wrong type"
userInfo:nil];
@throw myException;
}
}
- (void) removeObjectAtIndex:(NSUInteger)index
{
[realArray removeObjectAtIndex:index];
}
- (NSUInteger) count
{
return [realArray count];
}
- (id) objectAtIndex:(NSUInteger)index
{
return [realArray objectAtIndex:index];
}
static id NotSupported()
{
NSException* myException = [NSException
exceptionWithName:@"InvalidInitializer"
reason:@"Only initWithClass: and initWithClass:andCapacity: supported"
userInfo:nil];
@throw myException;
}
- (id)initWithArray:(NSArray *)anArray { return NotSupported(); }
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported(); }
- (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported(); }
- (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported(); }
- (id)initWithObjects:(id)firstObj, ... { return NotSupported(); }
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported(); }
@end
Benutzen als:
MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3];
[monoString addObject:@"A string"];
[monoString addObject:[NSNumber numberWithInt:42]];
[monoString addObject:@"Another string"];