2017-02-06 2 views
4

Ist das ein Fehler oder gibt es hier eine subtile Lektion?NSNumber reagiert positiv auf mutableCopy?

NSNumber *someNumber = @(1); 
[someNumber respondsToSelector:@selector(mutableCopy)]; // returns YES (!) 
[someNumber respondsToSelector:@selector(mutableCopyWithZone:)]; // returns NO 

von Apple LLVM 7.1 (iOS SDK 9,3)

Antwort

5

Dies liegt daran, NSObject selbst -mutableCopy implementiert (für alle Objekte, auch solche, die nicht übereinstimmen NSCopying oder NSMutableCopying), indem sie in -mutableCopyWithZone: Aufruf (so, dass die Dinge Umsetzung NSMutableCopying bekommen nur -mutableCopyWithZone: zu implementieren, ohne dass die Implementierung für -mutableCopy wiederholen).

Alles, was von NSObject erbt reagiert auf -mutableCopy, aber wenn man es tatsächlich genannt wird, wäre es zum Absturz, weil NSNumber nicht auf -mutableCopyWithZone: reagiert.

Sie können sehen, mit

assert([NSObject instanceMethodForSelector:@selector(mutableCopy)] == [NSNumber instanceMethodForSelector:@selector(mutableCopy)]) 

Analyse BBUM die einen Überblick über diese ziemlich gut - es gibt einige feine Rand Fällen, wenn diese Kontrollen dynamisch zu tun, weil Sie Antworten können Sie gar nicht erwarten.

+1

Danke für die Details, woher es kam! – bbum

+1

Tolle Infos. Und wenn ich mir die Dokumente für NSObject angesehen hätte: 'Dies ist eine bequeme Methode für Klassen, die das NSMutableCopying-Protokoll übernehmen. Eine Ausnahme wird ausgelöst, wenn es keine Implementierung für mutableCopyWithZone gibt. " –

+0

@BenFlynn Haha, ich habe mich nur halb daran erinnert. Dies ist nicht unbedingt eine leicht erkennbare Funktion in Code oder Dokumentation. –

4

, die ungerade ist. Ich würde nicht erwarten, dass die Klasse -mutableCopy implementiert. Dies könnte ein Fallout der Implementierung des markierten Zeigers sein (wenn ja, würde @ (REALLYBIGNUMBERTHATISNEARMAX) das Verhalten ändern).

Die subtile Lektion ist, dass Sie respondsToSelector: nicht wirklich für generische Funktionstests verwenden können. Noch können Sie isKindOfClass: verwenden. Es gibt viele Situationen, in denen es scheitern würde (NSArray vs. NSMutableArray verwendet, um sich sehr seltsam zu verhalten - kann immer noch-- bei dem Versuch, Introspektion verwenden, um Mutabilität zu bestimmen, zum Beispiel).

Introspection funktioniert gut für explizit deklarierte Situationen wie Delegation oder Datenquellen. Orte, an denen es eine @protocol Deklaration gibt, die speziell einige @optional Methoden definiert.