131

Is there a way to cast objects in objective-c much like the way objects are cast in VB.NET?

For example, I am trying to do the following:

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

However I am getting a compiler error since the 'list' property exists in the SelectionListViewController class but not on the FieldEditViewController even though SelectionListViewController inherits from FieldEditViewController.

This makes sense, but is there a way to cast myEditController to a SelectionListViewController so I can access the 'list' property?

For example in VB.NET I would do:

CType(myEditController, SelectionListViewController).list = listOfItems

Thanks for the help!

Billy
  • 2,406
  • 6
  • 28
  • 34

5 Answers5

233

Remember, Objective-C is a superset of C, so typecasting works as it does in C:

myEditController = [[SelectionListViewController alloc] init];
((SelectionListViewController *)myEditController).list = listOfItems;
Jim Puls
  • 79,175
  • 10
  • 73
  • 78
  • 21
    Or "Remember, Objective-C works like Java, just remember to add asterisks to variables that point to Obj-C objects." – Dan Rosenstark Jun 14 '10 at 03:43
  • 2
    Great answer. You could make it a little clearer by breaking out the cast and assignment into two lines. – Guido Anselmi Jun 03 '14 at 21:06
  • 1
    Typecasting in Objective-C is far more like old C than Java. Java hides most of this from the user, hence arguments that C should still be taught rather than Java as a first language. – csmith Jun 02 '16 at 14:18
  • I added front of my object (myVC *) and worked – Erhan Demirci May 11 '23 at 12:11
16

Typecasting in Objective-C is easy as:

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

However, what happens if first object is not UIView and you try to use it:

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

It will crash. And it's easy to find such crash for this case, but what if those lines are in different classes and the third line is executed only once in 100 cases. I bet your customers find this crash, not you! A plausible solution is to crash early, like this:

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

Those assertions doesn't look very nice, so we could improve them with this handy category:

@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

This is much better:

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

P.S. For collections type safety Xcode 7 have a much better than typecasting - generics

Community
  • 1
  • 1
Alexander Vasenin
  • 11,437
  • 4
  • 42
  • 70
12
((SelectionListViewController *)myEditController).list

More examples:

int i = (int)19.5f; // (precision is lost)
id someObject = [NSMutableArray new]; // you don't need to cast id explicitly
Sijmen Mulder
  • 5,767
  • 3
  • 22
  • 33
  • 7
    In general this is correct; you don't need to cast id in message expressions. But when using dot syntax to access and set properties, you must use a concrete type, not just id, so the compiler knows what method invocation to actually generate. (It can differ for properties with the same name.) – Chris Hanson Mar 29 '09 at 04:27
5

Sure, the syntax is exactly the same as C - NewObj* pNew = (NewObj*)oldObj;

In this situation you may wish to consider supplying this list as a parameter to the constructor, something like:

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

  if ( self ) {
    [self setList: anItemList];
  }

  return self;
}

Then use it like this:

myEditController = [[SelectionListViewController alloc] initWith: listOfItems];
Andrew Grant
  • 58,260
  • 22
  • 130
  • 143
0

Casting for inclusion is just as important as casting for exclusion for a C++ programmer. Type casting is not the same as with RTTI in the sense that you can cast an object to any type and the resulting pointer will not be nil.

stephen
  • 1,039
  • 14
  • 31