2012-05-11 11 views
11

Gibt es ein Objective-C-Äquivalent von C++ 's dynamic_cast?Objective-C dynamic_cast?

kann es sein, diese gefälscht werden:

MyClass *safeObject = [object isKindOfClass: [MyClass class]] 
         ? (MyClass *)originalObject : nil; 

Aber das ist eine Menge Code zu schreiben, auch wenn ich es nicht geben oft müssen.

Ich bin ein bisschen rostig so nicht ganz richtig sein könnte, aber ich glaube, das äquivalent in C++ wäre:

MyClass safeObject = dynamic_cast<MyClass>(orginalObject); 

Der Kontext ist es, einen Block, in dem der Parameter als eine Art a definiert ist generische Klasse, aber in diesem Block "weiß" ich, dass es eine spezifische Unterklasse ist. Trotzdem möchte ich nicht einfach blindlings mit (MyClass *)originalObject werben und einen theoretisch möglichen Fehler ignorieren.

Um klar zu sein, während ich eine dynamic_cast lieben würde, würde ich mit einer alternativen Annäherung glücklich sein, diesen Fall ebenso sicher zu behandeln.

+0

Im schlimmsten Fall könnten Sie dafür ein Makro schreiben. – JustSid

+4

Objective-C ist duck-typed. Ganz ehrlich, "komplizierte" Casts rudern irgendwie gegen die Sprache. – zneak

+0

Ja, ich denke ich habe hier wahrscheinlich die falsche Frage gestellt. Was auch immer für eine Frage, die ich * hätte haben sollen, hatte eine Antwort von "nimm einfach NSAsssert ([object isKindOfClass: [MyClass-Klasse]], @" blahblah ")' weil du es sowieso nicht erwartest. " :) –

Antwort

15

Wenn Sie bereit sind, das Ziel zu verwenden, -C++, können Sie dies ganz einfach schreiben:

template<typename T> inline T* objc_cast(id from) { 
    if ([from isKindOfClass:[T class]]) { 
     return static_cast<T*>(from); 
    } 
    return nil; 
} 

Dies sollte sich genau wie dynamic_cast<> mit Ausnahme von obj-c-Objekten verhalten.


Wenn Sie mit Vanille-Obj-C halten möchten, können Sie ein ähnliches Verhalten mit einer Klassenmethode auf NSObject erhalten:

@interface NSObject (Cast) 
+ (instancetype)cast:(id)from; 
@end 

@implementation NSObject (Cast) 
+ (instancetype)cast:(id)from { 
    if ([from isKindOfClass:self]) { 
     return from; 
    } 
    return nil; 
} 
@end 

Diese Version einfach nicht so schön ist, da Sie verwenden müssen so etwas wie

UIButton *button = [UIButton cast:someView]; 

sagen In beiden Versionen ist der resultierende Wert nil, wenn die Umwandlung fehlschlägt.

+0

Dieses zweite Beispiel ist * genau * wonach ich gesucht habe. Und irgendwie genial einfach. Vielen Dank. –

+0

das ist eine schöne Verwendung des instancetype-Operators, so dass der Compiler und die Xcode-Autocomplete sofort beginnen können, den konvertierten Typ zu verwenden – SystematicFrank

3
  1. Ich glaube nicht, dass es.
  2. Ich denke, der Platz für einen Fehler ist hier ziemlich klein.
  3. Aber wenn Sie darauf bestehen, wird ein Makro gut?
7

Versuchen Sie dieses Makro:

#define objc_dynamic_cast(obj, cls) \ 
    ([obj isKindOfClass:(Class)objc_getClass(#cls)] ? (cls *)obj : NULL) 

Und auch nicht vergessen

#include <objc/runtime.h> 

verwenden Sie es wie:

MyClass *safeObject = objc_dynamic_cast(originalObject, MyClass); 
+0

Ich hoffe, dass es Ihnen nichts ausmacht, aber ich wickelte Ihr Makro und fügte die (cls *), um eine Compiler-Warnung zu erfüllen. Gut gemacht! Ich habe gezögert, hier ein Makro zu verwenden, weil Xcode im Umfang bearbeitet wurde, aber es scheint wunderbar zu funktionieren. –

+0

Würde es Ihnen etwas ausmachen, eine Zeile hinzuzufügen, die zeigt, wie man dieses Makro benutzt (für grünere Außenseiter). Vielen Dank. – Wienke

+0

Ich habe eins hinzugefügt. (H2CO3: Wenn Sie das Gefühl haben, dass ich Ihre Antwort durcheinander bringe, zögern Sie einfach. Versuchen Sie, zukünftigen Lesern zu helfen!) –

Verwandte Themen