代码之家  ›  专栏  ›  技术社区  ›  Douglas Mayle

是否有一个等价于C++的动态转换在Objtovi-C中?

  •  5
  • Douglas Mayle  · 技术社区  · 15 年前

    如果我有两个类,子类和超类:

    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");
    

    我可以用ismemberofclass在objective-c中完成相同的事情,如下所示:

    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");
    

    有没有比这更简单的方法?

    (P.S.我知道我不必使用额外的id变量,但是我必须强制强制将super强制转换为subclass*,这有时会导致一个无效的引用,之后我必须清除它。然而,这种实现方式不那么复杂,它如下所示)

    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");
    
    6 回复  |  直到 9 年前
        1
  •  4
  •   PeyloW    15 年前

    可以在nsObject上添加类别以添加所需的功能。

    //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
    

    然后你可以这样做:

    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");
    
        2
  •  4
  •   Chris Suter    15 年前

    我使用宏:

    #define DYNAMIC_CAST(x, cls)                                \
      ({                                                        \
        cls *inst_ = (cls *)(x);                                \
        [inst_ isKindOfClass:[cls class]] ? inst_ : nil;        \
      })
    

    我稍微喜欢它使用nsObject上的类别,因为返回的对象是正确的类型(而不是ID),尽管我知道在大多数情况下,您只需将它分配给相同类型的变量即可。

        3
  •  2
  •   fbrereto    13 年前

    如果允许将任何C++投掷到混合中,可以避免宏并使用模板例程获得正确的类型:

    template <typename T, typename U>
    inline T* objc_cast(U* instance)
    {
        return [instance isMemberOfClass:[T class]] ?
                   static_cast<T*>(instance) :
                   nil;
    }
    

    然后,这个电话看起来很简单:

    sub_pointer = objc_cast<SubClass>(super);
    
        4
  •  1
  •   Benjohn    9 年前

    Xcode的最新版本提供 instancetype 并允许一个非常整洁的基于类别的解决方案。使用方法如下:

    TypeIWant *const thingIWant = [TypeIWant tryCast: thingIWantToCast];
    

    类别声明打开 NSObject

    @interface NSObject (DynamicCast)
    // Try a dynamic cast. Return nil if the class isn't compatible.
    +(instancetype) tryCast: (id) toCast;
    
    // Check a dynamic cast. Throw if the class isn't compatible.
    +(instancetype) checkCast: (id) toCast;
    @end
    

    类别实施

    @implementation NSObject (DynamicCast)
    
    +(instancetype) tryCast: (id) toCast
    {
        return [toCast isKindOfClass: self] ? toCast : nil;
    }
    
    +(instancetype) checkCast:(id)toCast
    {
        const id casted = [self tryCast: toCast];
        if(!casted)
        {
            [NSException raise: NSInvalidArgumentException format: @"Can't cast %@ to be an %@", toCast, NSStringFromClass(self)];
        }
        return casted;
    }
    
    @end
    

    使用

    这是一个 类方法 可赎回的 任何 班有 NSO对象 作为一个超级类(基本上,任何类)。

    你发送 tryCast: 方法 你希望投到 ,将要强制转换的对象作为参数。这样地 [ClassIWant tryCast: thingIWantCasted] .

    使用实例

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        UIPopoverController *const popoverDestination =
        [UIStoryboardPopoverSegue tryCast: segue].popoverController;
        if(popoverDestination)
        {
            UITableViewCell *const tableViewSender =
            [UITableViewCell tryCast: sender];
            if(tableViewSender)
            {
                // Things you need to do in this case.
                ...
    
        5
  •  0
  •   Douglas Mayle    15 年前

    我突然想到,我可以用三元运算符把这些都放到一行上,但这仍然有点混乱:

    SuperClass *super = [[SuperClass alloc] init];
    SubClass *sub = [[SubClass alloc] init];
    SubClass *sub_pointer;
    
    // One line, but still a bit wordy
    sub_pointer = [super isMemberOfClass:[SubClass class]] ? (SubClass*) super : nil;
    // Logs NO
    NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
    
    sub_pointer = [sub isMemberOfClass:[SubClass class]] ? (SubClass*) sub : nil;
    // Logs YES
    NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
    

    如果我要从函数中获取预期的变量,我必须将其缓存在一个ID变量中,以便这个版本工作。

    SubClass *sub_pointer;
    id generic_pointer;
    
    // One line, but still a bit wordy
    generic_pointer = (id) mySuperFunc();
    sub_pointer = [generic_pointer isMemberOfClass:[SubClass class]] ? generic_pointer : nil;
    // Logs NO
    NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
    
    generic_pointer = (id) mySubFunc();
    sub_pointer = [generic_pointer isMemberOfClass:[SubClass class]] ? generic_pointer : nil;
    // Logs YES
    NSLog(@"Is a subclass: %@", sub_pointer ? @"YES" : @"NO");
    
        6
  •  0
  •   unknown    15 年前

    基本上…

    id sub_pointer = [foo isMemberOfClass:AClass] ? foo : nil;
    NSLog(@"Is a subclass: %i", sub_pointer!=nil ); 
    

    似乎没有多大的词藻。