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


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

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

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

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

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

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

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

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

  • создайте новую ОС iPhone, приложение на основе просмотра в Xcode и назовите его TableTest
  • открыть TableTestViewController.xib в Interface Builder и перетащите a UITableView на предоставленную видовую поверхность.
  • подключить UITableView ' s 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;
}
  • стройте и идите, и вы должны увидеть слово Hello явиться в UITableView

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

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

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

#import "TableTestTableViewController.h"

и

IBOutlet TableTestTableViewController *myTableViewController;

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

4 54

4 ответа:

я последовал вашим шагам, воссоздал проект и столкнулся с той же проблемой. В основном вы почти там. Есть 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 под ними или над ними.

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

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

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

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

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

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

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