2014-10-10 4 views
0

У меня есть ViewController с UITableView. Поскольку я хотел разделить обработку данных, я создал собственный класс, который отвечает UITableViewDataSource.Передача информации из UITableViewDataSource в ViewController

Этот класс должен сначала получить данные из CoreData, а затем из REST API.

Каким образом DataSource может обратиться к ViewController, чтобы сообщить ему, чтобы вызвать reloadData в TableView? Какая у вас лучшая практика?

Я думал:

  • Кво данным DataSource и когда изменение массива вызов reloadData
  • Вручая блока (с [self.table reloadData]) к DataSource, который запускается на выполнение каждый раз, когда данные изменения в DataSource
  • Сделать свойство таблицы общедоступным на ViewController, чтобы DataSource мог вызвать reloadData (что мне не очень нравится как идея)
  • Имейте свойство на DataSource, который содержит ViewController с таблицей для использования в качестве делегата (который звучит для меня как петля)

Есть ли какие-нибудь умные способы сделать это? Или даже обычная практика, как это решить?

Update:

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

+0

Если вы хотите сохранить код, связанный с Разделить данные, почему бы не создать категорию на контроллере представления говорят 'MyTableVC + DataSource' или что-то еще? Будет ли это работать? Или вы действительно хотите, чтобы другой класс был источником данных? – GoodSp33d

+0

@ GoodSp33d, который не работает для меня, так как я хочу подключить разные источники данных к VC для получения разных данных из другого запроса данных о конечных точках/ядрах. – hashier

+0

Хорошо, вы хотите повторно использовать свой VC. Затем вы, как и другие, предложили создать интерфейс (протокол) и вызвать эти методы в источнике данных обычной таблицы. Другие классы могут реализовать эти методы в протоколе, чтобы предоставить данные VC – GoodSp33d

ответ

2

Без дополнительной информации это звучит так, как будто вам нужен обратный вызов здесь. Существует несколько методов, которые будут работать. Если у вас есть отношения 1 к 1 (это означает, что ваш источник данных должен только разговаривать с VC), то это хороший случай для:

1.) Делегат. Создайте собственный протокол делегатов для своего источника данных, а затем VC придерживайтесь этого протокола (будь то делегат).

2.) Сделайте то же самое, просто используя блок для обратного вызова.

KVO будет работать отлично, но два выше соответствуют вашему сценарию.

может добавить свойство tableView в свой собственный источник данных, но затем размывает строки, почему вы создали этот класс в первую очередь.

+0

Не могли бы вы объяснить, почему вы считаете, что делегат - лучший дизайн, чем KVO? – hashier

+1

Использование обратного вызова против KVO для этой ситуации объединяет ваши классы вместе более тесно и будет более читаемым. Вы контролируете, когда делегат уволен, но с KVO ваш наблюдатель будет вызван в любое время, когда он будет изменен подписчиком. Возможно, вы не хотите, чтобы ваша перезагрузка tableView была когда-либо, есть изменения в ее источнике данных. Предположим, вы используете KVO для подписки на изменения в NSMUtableArray, каждый раз, когда вы добавляете объект в этот массив, ваш слушатель (а) будет уведомлен. Скорее всего, вы хотите уведомить своего слушателя после того, как последний объект добавлен в ваш массив, и только один раз обновите его. – VaporwareWolf

1

Для таких ситуаций я предпочитаю делегатов.

@class CupcakePan; 

@protocol CupcakePanDelegate <NSObject> 
- (void)cupcakesAreReadyForPan:(CupcakePan *)pan; 
@end 

@interface CupcakePan : NSObject <UITableViewDataSource> 
@property (weak) id<CupcakePanDelegate> delegate; 
@end 

@implementation CupcakePan 
- (void)bakingComplete { 
    [self.delegate cupcakesAreReadyForPan:self]; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return [cupcakes count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return [make a CupcakeCell]; 
} 
@end 

@interface CupcakeViewController <CupcakePanDelegate> 
@end 

@implementation CupcakeViewController 
- (void)cupcakesAreReadyForPan:(CupcakePan *)pan { 
    [_tableView reloadData]; 
} 
@end 
+0

Спасибо за код, но мой главный вопрос - почему выбрать делегата над другими методами? Меня больше интересует дизайн, чем как реализовать дизайн в конце. – hashier

+0

Он помогает разделить ваш код, но также делает процесс более явным. При использовании 'NSNotificationCenter' вы немного нарушаете эту цепочку. Это не только затрудняет переход кода (нет горячей клавиши для отслеживания потоков уведомлений), но отладчик не будет перечислять исходную трассировку стека. –

0

Я часто использую NSNotificationCenter для этих типов взаимодействий.

В вашем источнике данных написать следующий код:

#define ABCNotificationName @"ABCNotificationName" 
#define ABCNotificationData @"ABCNotificationData" 

// ... 

[[NSNotificationCenter defaultCenter] postNotificationName:ABCNotificationName object:self userInfo:@{ ABCNotificationData: data }]; 

В контроллере просмотра выполните следующие действия:

-(void)loadView { 
    // setup your view 
    [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(datasourceUpdated:) name:ABCNotificationName object:dataSource]; 
} 

-(void)dealloc { 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

-(void)dataSourceUpdated:(NSNotification*)notification { 
    id data = notification.userInfo[ABCNotificationData]; 
    // respond to the event 
    [self.tableView reloadData]; 
} 

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

#define ABCNotificationName @"ABCNotificationName" 

// ... 

[[NSNotificationCenter defaultCenter] postNotificationName:ABCNotificationName object:self]; 

В контроллере просмотра выполните следующие действия:

-(void)loadView { 
    // setup your view 
    [NSNotificationCenter defaultCenter] addObserver:self selector:@selector(datasourceUpdated) name:ABCNotificationName object:dataSource]; 
} 

-(void)dealloc { 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

-(void)dataSourceUpdated { 
    // respond to the event 
    [self.tableView reloadData]; 
} 
+0

Спасибо за код, но мой главный вопрос - почему выбирать уведомления по другим методам? Меня больше интересует дизайн, чем как реализовать проект в конце. – hashier

+0

@hashier Когда вы используете уведомления для представления отношений, а не протокола, объекты очень слабо связаны друг с другом. Это означает, что когда что-то меняется, и, как правило, они делают это, легко изменить этот код. Честно говоря, отношения между чем-то вроде настольного источника данных и контроллера представления обычно не достаточно интересны, чтобы гарантировать определение протокола, а в Objective-C очень утомительно поддерживать эти отношения таким образом. – markshiz

+0

@hashier Например, добавление параметров и удаление параметров с помощью 'NSNotificationCenter' не требует изменения кода для существующего кода, а для делегата потребуется переопределение протокола, всех методов реализации и всех тестов. – markshiz