133

Is there a way to cast objects in Objective-C similar to how 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
0

5 Answers 5

235

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

myEditController = [[SelectionListViewController alloc] init];
((SelectionListViewController *)myEditController).list = listOfItems;
Sign up to request clarification or add additional context in comments.

4 Comments

Or "Remember, Objective-C works like Java, just remember to add asterisks to variables that point to Obj-C objects."
Great answer. You could make it a little clearer by breaking out the cast and assignment into two lines.
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.
I added front of my object (myVC *) and worked
17

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

Comments

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

1 Comment

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

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.