Objective-C: вы можете проверить неинициализированный указатель на статический тип класса? - PullRequest
2 голосов
/ 07 октября 2011

Я пытаюсь сделать что-то вроде:

в некотором объекте A:

UITableVIewController *viewController;
[someObjectB setupView: viewController];

в каком-то объекте B:

-(void) setupView:(UIViewController*)view
{
    if the pointer passed in is of type UITableViewController then ...
    say, for instance with: [[view class] isKindOfClass [UITableViewController class]]
    or: [view isKindOfClass [UITableViewController class]]
}

Однако у меня есть две проблемы: Во-первых, тот факт, что параметр входит в метод в B как UIViewController, который является суперклассом UITableView (что я делаю, потому что этот метод также настраивает другие типы контроллеров представления). Поэтому мне интересно, если я передам UITableViewController параметру метода типа UIViewController, isKindOfClass все еще делает динамическое связывание правильным? То есть среда выполнения проверяет тип содержимого независимо от статического типа указателя?

Во-вторых, обратите внимание, что я не инициализировал указатель в объекте A перед передачей его B. Я действительно хочу, чтобы B инициализировал его. Но тогда возникает вопрос: как проверить тип статического указателя на неинициализированном указателе? То есть внутри B: [view isKindOfClass [класс UITableViewController]] дает мне BAD_EXEC. Мое предположение, потому что я, очевидно, пытаюсь получить доступ к джул-указателю. Так есть ли способ по-прежнему тестировать на основе объявления статического типа указателя?

ADDENDUM: (потому что я добавил это как комментарий, извините)

Позвольте мне перефразировать эту часть вопроса в более конкретных терминах: я хочу, чтобы obj B создал переменную типа UITableViewController, передал ее A и дал A понять, что ему был дан указатель на UITableViewController, чтобы он мог фактически инициализироваться этот указатель на определенный подкласс UITableViewController и затем obj B передает этот инициализированный объект другому объекту.

Мое обоснование желания сделать это заключается в следующем сценарии: У меня есть приложение, основанное на навигационном контроллере. У него есть корневой контроллер с кнопками, и в зависимости от того, какая кнопка нажата, корневой контроллер создает и толкает контроллеры таблиц для различных таблиц базы данных, и, в свою очередь, при щелчке по строке этих таблиц создаются экземпляры таблиц и выводятся подробные сведения. контроллер.

Пока все хорошо, но из-за характера проекта я хочу, чтобы вся цепочка инстанции-толкания навигационного контроллера не зависела от того факта, что есть база данных и что таблицы и контроллеры детального просмотра на самом деле являются конкретными подклассами UITableViewController и UIViewController, соответственно.

Это означает, что поток будет:

1- При щелчке корневой контроллер передает универсальный UIViewController моему основному контроллеру.

2- Этот главный контроллер понимает, что ему передана общая таблица, инициализирует ее для определенного подкласса, определенного мной, и делает несколько вещей, чтобы предоставить ему данные из базы данных sql.

3 - Корневой контроллер, не заботясь о том, является ли универсальный UIViewController таблицей или нет, или даже подклассом UIViewController, просто передает его в navigationController.

Идея также состоит в том, что тогда мне не нужно включать заголовки для подклассов таблицы в корневой контроллер. Об этом знает только пользовательский главный контроллер.

Итак, в конце дня я вижу способ сделать это, имея возможность определить тип передаваемого указателя, независимо от того, равен ли этот указатель нулю, указывает на мусор или указывает на актуальный объект. Значение:

UIVIewController * a -> объявление статического типа, определенное во время компиляции.

a = [некоторый подкласс UIVIewController alloc] init]; -> динамический тип содержимого указателя, определенный во время выполнения, вероятно, по ссылкам через записи активации .. аналогично "виртуальному" в C ++

Ответы [ 3 ]

2 голосов
/ 07 октября 2011

В ответ на ваш первый вопрос, да - Objective C будет определять тип класса вашего объекта во время выполнения (динамически). В ответ на ваш второй вопрос, любой вызов метода, отправленный объекту nil, игнорируется, поэтому ни одна из ваших проверок класса на самом деле не будет работать. Однако вы не должны получать BAD_EXEC, если вы:

  • Инициализировал объект ранее и освободил его без установки значения nil, что привело к мусору по адресу его памяти
  • Передано в неинициализированной автоматической переменной, созданной компилятор для вас
  • По какой-то причине указал на какой-то бессмысленный адрес в памяти.

* РЕДАКТИРОВАТЬ *

Добавлен сценарий, в котором вы получите BAD_EXEC, а также см. Ссылку ниже для нескольких ошибок при тестировании на равенство классов, особенно с помощью метода isKindOfClass.

В Objective-C, что эквивалентно ключевому слову "instanceof" в Java?

2 голосов
/ 07 октября 2011

Как уже отмечали другие, то, что вы просите, невозможно. Когда вы передаете переменную методу, он отправляет только значение, а не тип. Кроме того, среда выполнения не знает тип переменной в методе. Любая обработка типов переменных выполняется компилятором. Среда выполнения может знать только класс объекта, который содержит переменная.

В качестве альтернативы, если вы можете изменить сигнатуру вашего метода, вы можете добавить параметр, который указывает тип создаваемого объекта. Вызывающему методу все еще не нужно знать точный тип объекта, просто является ли он контроллером табличного представления или нет. Вот пример, который использует перечисление для хранения различных типов.

// header

enum ViewControllerType {
    ViewControllerNormal = 0,
    ViewControllerTableView
};
- (void)setupView:(UIViewController **)view ofType:(enum ViewControllerType)type;

// implementation

- (void)setupView:(UIViewController **)view ofType:(enum ViewControllerType)type {
    if(!view) {
        NSLog(@"setupView:ofType: received nil pointer");
        return;
    }
    switch(type) {
        case ViewControllerNormal:
            // create normal UIViewController type
            break;
        case ViewControllerTableView:
            // create UITableViewController type
            break;
        default:
            NSLog(@"setupView:ofType: received unknown type: %i",type);
            return;
    }
}

Используется как:

UIViewController *view;
[creatorObject setupView:&view ofType:ViewControllerNormal];
// or
UITableViewController *tableView;
[creatorObject setupView:&tableView ofType:ViewControllerTableView];
2 голосов
/ 07 октября 2011

Objective-C является языком передачи по значению, как и C. Вы не можете инициализировать viewController в вашем объекте A с помощью кода, который у вас есть.Инициализируйте его, передайте его адрес setupView:, а затем инициализируйте его при необходимости:

UITableVIewController *viewController = nil;
[someObjectB setupView:&viewController];

и:

-(void)setupView:(UIViewController**)view
{
   if (*view == nil)
      // initialize it  - *view = [[blah alloc] init] or whatever
   else
       ...

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...