如何在Objective-C中投射对象


123

有没有一种方法可以像在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]; 

但是我遇到了编译器错误,因为即使SelectionListViewController继承自FieldEditViewController,SelectionListViewController类中也存在list属性,但FieldEditViewController中不存在。

这是有道理的,但是有一种方法可以将myEditController强制转换为SelectionListViewController,以便我可以访问'list'属性?

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

CType(myEditController, SelectionListViewController).list = listOfItems

谢谢您的帮助!

Answers:


216

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

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

21
或“记住,Objective-C的工作方式类似于Java,只需记住在指向Obj-C对象的变量中添加星号即可。”
Dan Rosenstark 2010年

1
好答案。您可以通过将演员表和作业分成两行来使其更加清晰。
Guido Anselmi 2014年

1
Objective-C中的类型转换比Java更像旧C。Java对用户隐藏了其中的大部分内容,因此仍然有这样的论点,即仍然应该教导C而不是将Java作为第一语言。
csmith

11
((SelectionListViewController *)myEditController).list

更多示例:

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

7
总的来说,这是正确的。您无需在消息表达式中强制转换id。但是,当使用点语法访问和设置属性时,必须使用一种具体的类型,而不仅仅是id,这样编译器就知道实际生成哪种方法调用。(名称相同的属性可能有所不同。)
克里斯·汉森

9

在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个情况下仅执行一次,该怎么办。我敢打赌,您的客户会发现此崩溃,而不是您!一个可行的解决方案是尽早崩溃,如下所示:

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]];

PS对于集合,类型安全性Xcode 7比类型转换要好得多- 泛型


4

当然,语法与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];

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.