Як відкинути об'єкт у Objective-C


123

Чи є спосіб викидати об'єкти в object-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, щоб я міг отримати доступ до властивості "список"?

Наприклад, у VB.NET я би зробив:

CType(myEditController, SelectionListViewController).list = listOfItems

Дякую за допомогу!

Відповіді:


216

Пам'ятайте, Objective-C - це набір C, тому набір клавіш працює так, як це робиться в C:

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

21
Або "Пам'ятайте, Objective-C працює як Java, просто не забудьте додати зірочки до змінних, які вказують на об'єкти Obj-C."
Дан Розенстарк

1
Чудова відповідь. Ви можете зробити це трохи зрозумілішим, розбивши групу та призначте її на два рядки.
Гвідо Ансельмі

1
Набір клавіш в Objective-C набагато більше схожий на старий C, ніж на Java. 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, тому компілятор знає, який метод виклику методу насправді генерувати. (Це може відрізнятись за властивостями з однаковою назвою.)
Кріс Хансон,

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 має набагато краще, ніж 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];

0

Кастинг для включення так само важливий, як і кастинг для виключення для програміста C ++. Кастинг типів не такий, як з RTTI в тому сенсі, що ви можете кинути об'єкт на будь-який тип, і отриманий вказівник не буде нульовим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.