【问题标题】:How to cast an object in Objective-C如何在 Objective-C 中转换对象
【发布时间】:2010-10-16 00:00:23
【问题描述】:

有没有一种方法可以像在 VB.NET 中一样在 Objective-c 中转换对象?

例如,我正在尝试执行以下操作:

// create the view controller for the selected item
FieldEditViewController *myEditController;
switch (selectedItemTypeID) {
    case 3:
        myEditController = [[SelectionListViewController alloc] init];
        myEditController.list = listOfItems;
        break;
    case 4:
        // set myEditController to a diff view controller
        break;
}

// load the view
[self.navigationController pushViewController:myEditController animated:YES];
[myEditController release]; 

但是我得到一个编译器错误,因为“list”属性存在于 SelectionListViewController 类中,但不在 FieldEditViewController 上,即使 SelectionListViewController 继承自 FieldEditViewController。

这是有道理的,但是有没有办法将 myEditController 转换为 SelectionListViewController 以便我可以访问“列表”属性?

例如在 VB.NET 中我会这样做:

CType(myEditController, SelectionListViewController).list = listOfItems

感谢您的帮助!

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    请记住,Objective-C 是 C 的超集,因此类型转换的工作方式与在 C 中一样:

    myEditController = [[SelectionListViewController alloc] init];
    ((SelectionListViewController *)myEditController).list = listOfItems;
    

    【讨论】:

    • 或者“记住,Objective-C 的工作方式与 Java 类似,只要记住给指向 Obj-C 对象的变量添加星号。”
    • 很好的答案。您可以通过将演员表和作业分成两行来使其更清晰。
    • Objective-C 中的类型转换更像是旧的 C 而不是 Java。 Java 对用户隐藏了其中的大部分内容,因此仍应教授 C 而不是 Java 作为第一语言的争论。
    【解决方案2】:
    ((SelectionListViewController *)myEditController).list
    

    更多示例:

    int i = (int)19.5f; // (precision is lost)
    id someObject = [NSMutableArray new]; // you don't need to cast id explicitly
    

    【讨论】:

    • 一般来说这是正确的;您不需要在消息表达式中转换 id 。但是当使用点语法访问和设置属性时,必须使用具体类型,而不仅仅是 id,这样编译器就知道要实际生成什么方法调用。 (同名的属性可能不同。)
    【解决方案3】:

    当然,语法和 C 完全一样——NewObj* pNew = (NewObj*)oldObj;

    在这种情况下,您可能希望考虑将此列表作为参数提供给构造函数,例如:

    // SelectionListViewController
    -(id) initWith:(SomeListClass*)anItemList
    {
      self = [super init];
    
      if ( self ) {
        [self setList: anItemList];
      }
    
      return self;
    }
    

    然后像这样使用它:

    myEditController = [[SelectionListViewController alloc] initWith: listOfItems];
    

    【讨论】:

      【解决方案4】:

      对于 C++ 程序员来说,强制包含与强制排除同样重要。类型转换与 RTTI 不同,因为您可以将对象转换为任何类型,并且结果指针不会为 nil。

      【讨论】:

        【解决方案5】:

        Objective-C 中的类型转换很简单:

        NSArray *threeViews = @[[UIView new], [UIView new], [UIView new]];
        UIView *firstView = (UIView *)threeViews[0];
        

        但是,如果第一个对象不是 UIView 而您尝试使用它会发生什么:

        NSArray *threeViews = @[[NSNumber new], [UIView new], [UIView new]];
        UIView *firstView = (UIView *)threeViews[0];
        CGRect firstViewFrame = firstView.frame; // CRASH!
        

        它会崩溃。对于这种情况很容易找到这样的崩溃,但是如果这些行在不同的类中并且第三行在 100 个案例中只执行一次怎么办。我敢打赌你的客户发现了这次崩溃,而不是你!一个合理的解决方案是crash early,如下所示:

        UIView *firstView = (UIView *)threeViews[0];
        NSAssert([firstView isKindOfClass:[UIView class]], @"firstView is not UIView");
        

        那些断言看起来不太好,所以我们可以用这个方便的类别来改进它们:

        @interface NSObject (TypecastWithAssertion)
        + (instancetype)typecastWithAssertion:(id)object;
        @end
        
        
        @implementation NSObject (TypecastWithAssertion)
        
        + (instancetype)typecastWithAssertion:(id)object {
            if (object != nil)
                NSAssert([object isKindOfClass:[self class]], @"Object %@ is not kind of class %@", object, NSStringFromClass([self class]));
            return object;
        }
        
        @end
        

        好多了

        UIView *firstView = [UIView typecastWithAssertion:[threeViews[0]];
        

        附:对于集合类型安全,Xcode 7 比类型转换要好得多 - generics

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-27
          • 1970-01-01
          • 1970-01-01
          • 2011-06-10
          相关资源
          最近更新 更多