Warum verwenden (id) in einer Methodensignatur, wenn (NSObject *) würde genauer sein?

StackOverflow https://stackoverflow.com/questions/1829028

  •  11-09-2019
  •  | 
  •  

Frage

Jedes Mal, wenn ich eine Methode in meinem eigenen Code implementieren, oder zurückgeben Objekte von mehr als eine Klasse akzeptieren kann, versuche ich immer zur Verfügung, die spezifischste geordnete Klasse zu verwenden. wenn ich eine Methode implementieren würde, die eine NSArray * oder eine NSDictionary * abhängig von seinem Eingang könnten zurückkehren, ich würde zum Beispiel, dass Methode eines Rückgabetyp von NSObject *, denn das ist die unmittelbarste gemeinsame Oberklasse ist. Hier ein Beispiel:

@interface MyParser()
- (BOOL)stringExpressesKeyValuePairs:(NSString *)string;
- (BOOL)stringExpressesAListOfEntities:(NSString *)string;
- (NSArray *)parseArrayFromString:(NSString *)string;
- (NSDictionary *)parseDictionaryFromString:(NSString *)string;
@end

@implementation MyParser
- (NSObject *)parseString:(NSString *)string {
    if ([self stringExpressesKeyValuePairs:string]) {
        return [self parseDictionaryFromString:string];
    }
    else if ([self stringExpressesAListOfEntities:string]) {
        return [self parseArrayFromString:string];
    }
}
// etc...
@end

Ich habe viele Fälle, in Foundation und andere APIs bemerkt, wo Apple-(id) in bestimmten Methodensignaturen verwendet, wenn (NSObject *) genauer sein würde. Zum Beispiel ist hier ein Verfahren zur Herstellung NSPropertyListSerialization:

+ (id)propertyListFromData:(NSData *)data 
          mutabilityOption:(NSPropertyListMutabilityOptions)opt 
                    format:(NSPropertyListFormat *)format 
          errorDescription:(NSString **)errorString

Die möglichen Rückgabetypen von dieser Methode sind NSData, NSString, NSArray, NSDictionary, NSDate und NSNumber. Es scheint mir, dass ein Rückgabetyp (NSObject *) wäre eine bessere Wahl als (id), da der Anrufer dann ohne eine Art Guss wie behalten NSObject Methoden aufrufen zu können.

Ich versuche, im Allgemeinen der Idiome von dem offiziellen Rahmen etabliert zu emulieren, aber Ich mag auch verstehen, was sie motiviert. Ich bin sicher, dass Apple einigen triftigen Grund für die Verwendung von (id) in Fällen wie diesen, aber ich bin nur sehe es nicht. Was bin ich?

War es hilfreich?

Lösung

id Mit teilt den Compiler es wird ein Objekt unbekannten Typs sein. Mit NSObject würde der Compiler erwartet, dass Sie nur dann sein, um Nachrichten mit zur Verfügung zu NSObject. So ... Wenn Sie wissen, ein Array zurückgegeben wurde und es als id gegossen, können Sie objectAtIndex nennen: ohne Compiler-Warnungen. Während bei einer Besetzung von NSObject Rückkehr, werden Sie Warnungen erhalten.

Andere Tipps

Der Grund, warum (id) in Methodendeklarationen verwendet wird, ist zweifach:

(1) Das Verfahren, jede Art nehmen oder zurückkehren. NSArray enthält jedes Zufallsobjekt und damit objectAtIndex: wird ein Objekt von jeder beliebigen Art zurückzukehren. Casting es zu NSObject* oder id <NSObject> wäre aus zwei Gründen falsch sein; Zunächst kann ein Array nicht NSObject Unterklassen enthalten, solange sie eine bestimmte kleine Menge von Methoden und zum anderen implementieren, eine bestimmte Rückgabetyp würde Gießen erfordern.

(2) Objective-C unterstützt keine covariant Erklärungen. Bedenken Sie:

@interface NSArray:NSObject
+ (id) array;
@end

Jetzt können Sie +array sowohl NSArray und NSMutableArray nennen. Die erstere liefert einen unveränderlichen-Array und das letztere ein veränderliches Array. Wegen des Objective-C-Mangels an covariant Erklärung Unterstützung, wenn die oben als Rückkehr (NSArray*) erklärt wurden, Kunden der Subklassen Methode müßten `(NSMutableArray *) werfen. Hässlich, zerbrechlich, und fehleranfällig. Somit ist der gattungs verwendet wird, im Allgemeinen, die einfachste Lösung.

Also ... wenn Sie eine Methode deklarieren, die eine Instanz einer bestimmten Klasse zurückgibt, typisieren ausdrücklich. Wenn Sie eine Methode deklarieren, die überschrieben werden und dass überschreiben kann eine Unterklasse zurückgeben und die Tatsache, dass es sich um eine Unterklasse an Kunden ausgesetzt werden zurückgibt, dann (id) verwenden.

Keine Notwendigkeit, einen Fehler in Datei -. Gibt es mehrere bereits


Beachten Sie, dass ObjC hat nun begrenzt Kovarianz Unterstützung durch das instancetype Schlüsselwort.

d. NSArray des + Array-Verfahren nun erklärt werden könnte, wie:

+ (instancetype) array;

Und der Compiler würde [NSMutableArray array] als Rückkehr ein NSMutableArray* behandeln, während [NSArray array] als Rückkehr NSArray* betrachtet würde.

Sie können Anwender schon -retain auf Zeiger von Typ-ID ohne Gießen. Wenn Sie einen bestimmten Supertyp verwenden, werden Sie den Zeiger jedes Mal werfen müssen Sie eine Unterklasse Methode aufrufen, um Compiler-Warnungen zu vermeiden. Verwenden Sie id so wird der Compiler nicht Sie warnen und besser bedeuten Ihre Absicht.

(id) wird oft auch zurückgeführt, um Objekte zu ermöglichen subclassed leichter werden. Zum Beispiel in initializer und bequeme Methoden, Rückkehr (id) bedeutet, dass jede Unterklasse muss nicht die Methoden des übergeordneten Klasse außer Kraft setzen, es sei denn es einen bestimmten Grund, dies zu tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top