How to cast an object in Objective-C

Objective C

Objective C Problem Overview


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!

Objective C Solutions


Solution 1 - Objective C

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

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

Solution 2 - Objective C

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

Solution 3 - Objective C

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

Solution 4 - Objective C

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

Solution 5 - Objective C

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBillyView Question on Stackoverflow
Solution 1 - Objective CJim PulsView Answer on Stackoverflow
Solution 2 - Objective CAlexander VaseninView Answer on Stackoverflow
Solution 3 - Objective CSijmen MulderView Answer on Stackoverflow
Solution 4 - Objective CAndrew GrantView Answer on Stackoverflow
Solution 5 - Objective CstephenView Answer on Stackoverflow