Проблема UITableView при использовании отдельного делегата / источника данных - PullRequest
54 голосов
/ 31 октября 2008

Общее описание:

Чтобы начать с того, что работает, у меня есть UITableView, который был помещен в сгенерированный Xcode вид с помощью Interface Builder. Владелец файла представления установлен в сгенерированный XCode подкласс UIViewController. К этому подклассу я добавил рабочие реализации numberOfSectionsInTableView: tableView:numberOfRowsInSection: и tableView:cellForRowAtIndexPath:, а таблицы dataSource и delegate подключены к этому классу через владельца файла в Интерфейсном Разработчике.

Приведенная выше конфигурация работает без проблем. Проблема возникает, когда я хочу переместить реализации dataSource и delegate этого табличного представления в отдельный класс, скорее всего из-за того, что есть другие элементы управления в представлении, кроме табличного представления, и я хотел бы переместить табличное представление связанный код для своего собственного класса. Для этого я пытаюсь сделать следующее:

  • Создайте новый подкласс UITableViewController в Xcode
  • Переместите зарекомендовавшие себя реализации numberOfSectionsInTableView:, tableView:numberOfRowsInSection: и tableView:cellForRowAtIndexPath: в новый подкласс
  • Перетащите UITableViewController на верхний уровень существующего XIB в InterfaceBuilder, удалите UIView / UITableView, которые автоматически создаются для этого UITableViewController, затем установите UITableViewController класс, соответствующий новому подклассу
  • Удалите ранее работающие UITableView существующие dataSource и delegate соединения и подключите их к новым UITableViewController

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

  • Когда загружается UITableView, я получаю сообщение об ошибке выполнения, указывающее, что я посылаю tableView:cellForRowAtIndexPath: объекту, который его не распознает
  • Когда загружается UITableView, проект без ошибок вырывается в отладчик
  • Нет ошибки, но UITableView не появляется

С некоторой отладкой и созданием базового проекта только для воспроизведения этой проблемы я обычно вижу третий вариант выше (без ошибки, но без видимого табличного представления). Я добавил несколько вызовов NSLog и обнаружил, что, хотя numberOfSectionsInTableView: и numberOfRowsInSection: оба вызывают, cellForRowAtIndexPath: нет. Я убежден, что упускаю что-то действительно простое и надеялся, что ответ может быть очевиден для кого-то с большим опытом, чем у меня. Если это не будет легким ответом, я был бы рад обновить с некоторым кодом или примером проекта. Спасибо за ваше время!

Полные шаги для воспроизведения:

  • Создайте новую iPhone OS, приложение для просмотра в Xcode и назовите его TableTest
  • Откройте TableTestViewController.xib в Интерфейсном Разработчике и перетащите UITableView на предоставленную поверхность просмотра.
  • Подключите выходы UITableView dataSource и delegate к Владельцу файла, который уже должен представлять класс TableTestViewController. Сохраните ваши изменения
  • Вернувшись в Xcode, добавьте следующий код в TableTestViewController.m:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSLog(@"Returning num sections");
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSLog(@"Returning num rows");
    return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"Trying to return cell");
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.text = @"Hello";
    NSLog(@"Returning cell");
    return cell;
}
  • Build and Go, и вы должны увидеть слово Hello в UITableView

  • Теперь, чтобы попытаться переместить логику этого UITableView в отдельный класс, сначала создайте новый файл в XCode, выбрав UITableViewController подкласс и вызвав класс TableTestTableViewController

  • Удалите приведенный выше фрагмент кода из TableTestViewController.m и поместите его в TableTestTableViewController.m, заменив реализацию по умолчанию этих трех методов на нашу.
  • Вернитесь в Интерфейсный Разработчик в том же файле TableTestViewController.xib, перетащите UITableViewController в главное окно IB и удалите новый объект UITableView, который автоматически пришел с ним
  • Установить класс для этого нового UITableViewController в TableTestTableViewController
  • Удалите привязки dataSource и delegate из существующих ранее работающих UITableView и заново соедините те же две привязки с новыми TableTestTableViewController, которые мы создали.
  • Сохраняйте изменения, Build and Go, и если вы получаете результаты, которые я получаю, обратите внимание, что UITableView больше не работает должным образом

Решение: С некоторыми дополнительными возможностями по устранению неполадок и помощью iPhone Developer Forums , я задокументировал решение! Основному подклассу UIViewController проекта требуется выход, указывающий на экземпляр UITableViewController. Для этого просто добавьте в заголовок основного представления следующее (TableTestViewController.h):

#import "TableTestTableViewController.h"

и

IBOutlet TableTestTableViewController *myTableViewController;

Затем в Интерфейсном Разработчике подключите новый выход от Владельца файла к TableTestTableViewController в главном окне IB. Никаких изменений не требуется в части пользовательского интерфейса XIB. Просто наличие этой розетки, даже если ни один пользовательский код не использует ее напрямую, полностью решает проблему. Спасибо тем, кто помог и поблагодарил BaldEagle на форумах разработчиков iPhone за поиск решения.

Ответы [ 4 ]

23 голосов
/ 01 ноября 2008

Я выполнил ваши шаги, пересоздал проект и столкнулся с той же проблемой. В основном вы почти там. Отсутствуют 2 вещи (после исправления это работает):

  • Вам необходимо подключить tableView из TableTestTableViewController к UITableView, имеющемуся на экране. Как я уже говорил, поскольку это не IBOutlet, вы можете переопределить свойство tableView и сделать его и IBOutlet:

    @interface TableTestTableViewController : UITableViewController {
        UITableView *tableView;
    }
    
    @property (nonatomic, retain) IBOutlet UITableView *tableView;
    
  • Далее следует добавить ссылку на TableTestTableViewController и сохранить ее в TableTestViewController. В противном случае ваш TableTestTableViewController может быть освобожден (после загрузки пера, на котором ничего не висит), и именно поэтому вы видите ошибочные результаты, сбои или отсутствие показа. Для этого добавьте:

    @interface TableTestViewController : UIViewController {
        TableTestTableViewController *tableViewController;
    }
    
    @property (nonatomic, retain) IBOutlet TableTestTableViewController  *tableViewController;
    

    и подключите его в Интерфейсном Разработчике к экземпляру TableTestTableViewController.

С учетом вышесказанного это работало нормально на моей машине.

Также я думаю, что было бы хорошо указать мотивацию всего этого (вместо того, чтобы просто использовать UITableViewController со своим UITableView). В моем случае это было использование других представлений, которые просто UITableView на том же экране содержимого. Поэтому я могу добавить другие UILabels или UIImages под UIView и показать UITableView под ними или над ними.

5 голосов
/ 07 марта 2009

Я просто потратил много часов на то, чтобы выдернуть свои волосы, пытаясь понять, почему UITableView не появится, когда я встроил его в отдельный, а не в основной. Я наконец нашел ваше обсуждение выше и понял, что это потому, что мои UITableViewController не были сохранены! Видимо, свойства делегата и источника данных UITableView не помечены как «сохранить», и поэтому мое перо загружалось, но контроллер подбрасывался ... И из-за чудес target-c я получил ошибку no сообщений от этого ... Я до сих пор не понимаю, почему он не вылетел. Я знаю, что видел «сообщение, отправленное выпущенному ххх» раньше ... почему он не дал мне один из них?!?

Я думаю, что большинство разработчиков предположили бы, что структура, которую они создают в конструкторе интерфейсов, будет содержаться в более широком контексте (Nib) и не подлежит выпуску. Я думаю, я знаю, почему они это делают .. так что iPhone может сбросить и перезагрузить части пера из-за недостатка памяти. Но человек, это было трудно понять.

Может кто-нибудь сказать мне, где я должен был прочитать об этом поведении в документах?

Также - о подключении вида. Во-первых, если вы перетащите один из построителя пользовательского интерфейса, вы увидите, что они подключают свойство представления (которое является IBOutlet) к табличному представлению. Нет необходимости выставлять tableView, который, кажется, устанавливается внутри. На самом деле, вам даже не нужно устанавливать представление, если вы не хотите viewDidLoad уведомление. Я только что разорвал соединение вида между моими uitableview и uitableviewcontroller (только набор делегатов и источник данных), и оно, очевидно, работает нормально.

3 голосов
/ 31 октября 2008

Да, по какой-то причине (пожалуйста, укажите, если кто-нибудь знает, почему ...) tableView свойство UITableViewController не отображается как IBOutlet, даже если это публичная собственность. Поэтому, когда вы используете Interface Builder, вы не можете видеть это свойство для подключения к вашему другому UITableView. Таким образом, в вашем подклассе вы можете создать свойство tableView, помеченное как IBOutlet, и подключить его.

Все это кажется хакерским и обходным решением, но, похоже, это единственный способ отделить UITableViewController's UITableView и поместить его где-то еще в иерархию пользовательского интерфейса. Я столкнулся с той же проблемой, когда пытался создать представление, в котором есть вещи, отличные от UITableView, и именно так я решил это ... Это правильный подход ???

2 голосов
/ 11 марта 2012

Я смог сделать эту работу. Я построил действительно хорошую приборную панель с 4 TableViews и веб-просмотром с видео. Ключ имеет отдельные контроллеры tableView и IBOutlets для других контроллеров tableview, определенных в контроллере представления. В UIB вам просто нужно подключить другие контроллеры табличного представления к владельцу файла контроллера представления. Затем подключите таблицы к соответствующим контроллерам представления для источника данных и делегата.

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