If I have two classes, SubClass and SuperClass:
SuperClass *super = new SuperClass();
SubClass *sub = new SubClass();
SubClass *sub_pointer;
// **The nice one-line cast below**
sub_pointer = dynamic_cast<SubClass*> super;
// Prints NO
printf("Is a subclass: %s\n", sub_pointer ? "YES" : "NO");
sub_pointer = dynamic_cast<SubClass*> sub;
// Prints YES
printf("Is a subclass: %s\n", sub_pointer ? "YES" : "NO");
I can accomplish the same thing in objective-C with isMemberOfClass as follows:
SuperClass *super = [[SuperClass alloc] init];
SubClass *sub = [[SubClass alloc] init];
SubClass *sub_pointer;
id generic_pointer;
// Not as easy:
generic_pointer = super;
if ([generic_pointer isMemberOfClass:[SubClass class]]) {
sub_pointer = generic_pointer;
} else {
sub_pointer = nil;
}
// Logs NO
NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
generic_pointer = sub;
if ([generic_pointer isMemberOfClass:[SubClass class]]) {
sub_pointer = generic_pointer;
} else {
sub_pointer = nil;
}
// Logs YES
NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
Is there an easier way than this?
(P.S. I know I don't have to use the extra id variable, but then I would have to force cast super to SubClass*, which would sometimes result in an invalid reference that I would have to clean up afterwards. That implementation, however, is less wordy, and it's below)
SuperClass *super = [[SuperClass alloc] init];
SubClass *sub = [[SubClass alloc] init];
SubClass *sub_pointer;
// Not as easy:
sub_pointer = (SubClass*) super;
if (![sub_pointer isMemberOfClass:[SubClass class]]) {
sub_pointer = nil;
}
// Logs NO
NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
sub_pointer = (SubClass*) sub;
if (![sub_pointer isMemberOfClass:[SubClass class]]) {
sub_pointer = nil;
}
// Logs YES
NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
You could add a category on NSObject to add the functionality you want.
//NSObject+DynamicCast.h
@interface NSObject (DynamicCast)
-(id)objectIfMemberOfClass:(Class)aClass;
@end
//NSObject+DynamicCast.m
@implementation NSObject (DynamicCast)
-(id)objectIfMemberOfClass:(Class)aClass;
{
return [self isMemberOfClass:aClass] ? self : nil;
}
@end
Then you could do this:
SuperClass *super = [[SuperClass alloc] init];
SubClass *sub = [[SubClass alloc] init];
SubClass *sub_pointer;
id generic_pointer;
// **The nice one-line cast below**
sub_pointer = [super objectIfMemberOfClass:[SubClass class]];
// Prints NO
printf("Is a subclass: %s\n", sub_pointer ? "YES" : "NO");
sub_pointer = [sub objectIfMemberOfClass:[SubClass class]];
// Prints YES
printf("Is a subclass: %s\n", sub_pointer ? "YES" : "NO");
I use a macro:
#define DYNAMIC_CAST(x, cls) \
({ \
cls *inst_ = (cls *)(x); \
[inst_ isKindOfClass:[cls class]] ? inst_ : nil; \
})
I marginally prefer it to using a category on NSObject because the returned object is the correct type (rather than id), although I realise that in most cases you’re simply going to assign it to a variable of the same type anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With