Есть ли способ сбрасывать объекты в objective-c так же, как объекты в VB.NET?
Например, я пытаюсь сделать следующее:
// 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, чтобы я мог получить доступ к свойству "list"?
Например, в VB.NET я бы сделал:
CType(myEditController, SelectionListViewController).list = listOfItems
Спасибо за помощь!
Ответ 1
Помните, что Objective-C является надмножеством C, поэтому приведение типов работает так же, как и в C:
myEditController = [[SelectionListViewController alloc] init];
((SelectionListViewController *)myEditController).list = listOfItems;
Ответ 2
((SelectionListViewController *)myEditController).list
Другие примеры:
int i = (int)19.5f; // (precision is lost)
id someObject = [NSMutableArray new]; // you don't need to cast id explicitly
Ответ 3
Типизация в 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]];
P.S. Для типов коллекций безопасность Xcode 7 намного лучше, чем typecasting - generics
Ответ 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];
Ответ 5
Кастинг для включения столь же важен, как и кастинг для исключения для программиста на С++. Тип отливки не совпадает с RTTI в том смысле, что вы можете наложить объект на любой тип, а полученный указатель не будет равен нулю.