Заполните UITableView в классе ViewController из отдельного класса DataController, который использует централизованную отправку

У меня есть UITableView в классе ViewController. Класс ViewController использует пользовательский контроллер данных (указанный в AppDelegate). В классе dataController я извлекаю некоторый JSON из Интернета, анализирую его в NSMutableArray, а затем использую эти данные для заполнения UITableView в ViewController.

Все это отлично работает, за исключением заметной задержки при запуске приложения, поскольку требуется время, чтобы получить JSON и работать с ним. Я хотел бы показать пустой UITableView с индикатором активности, пока эти данные загружаются. К сожалению, всякий раз, когда я помещаю код класса dataController в очередь отправки, UITableView никогда не заполняется данными (данные загружаются в соответствии с журналом). Я вижу только пустой стол.

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

Соответствующий код:

из класса dataController:

- (void)initializeDefaultDataList {
    NSMutableArray *dataList = [[NSMutableArray alloc] init];
    self.masterDataList = dataList;
    dispatch_queue_t myQueue = dispatch_queue_create("name.queue.my", NULL);
    dispatch_async(myQueue, ^{
        NSString *jsonString = [JSONHelper JSONpostString:@"http://webservice/getData"];

        NSError *jsonError = nil;
        //convert string to dictionary using NSJSONSerialization
        NSDictionary *jsonResults = [NSJSONSerialization JSONObjectWithData: [jsonString dataUsingEncoding:NSUTF8StringEncoding] 
                                                                    options: NSJSONReadingMutableContainers 
                                                                      error: &jsonError];
        if (jsonError) NSLog(@"[%@ %@] JSON error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), jsonError.localizedDescription);

        NSArray *dataArray = [jsonResults objectForKey:@"d"];

        for (NSString *dataItem in dataArray) {
            [self addDataWithItem:dataItem];
        }
    });
}

от AppDelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
    MyMasterViewController *firstViewController = (MyMasterViewController *)[[navigationController viewControllers] objectAtIndex:0];
    MyDataController *aDataController = [[MyDataController alloc] init];
    firstViewController.dataController = aDataController;
    return YES;
}

из ViewController:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    //would this go here?
    dispatch_async(dispatch_get_main_queue(), ^{
        MyObject *objectAtIndex = [self.dataController objectInListAtIndex:indexPath.row];
        [[cell textLabel] setText:objectAtIndex.name];
    });
    return cell;
}

В случае, если вы не можете сказать, что я действительно новичок в iOS и Objective C. Любая помощь или подсказки, которые вы можете дать, будут очень признательны. Я даже не уверен, правильно ли я выражаю свой вопрос - просто кажется, что то, что я хочу сделать, не должно быть таким сложным. Спасибо!

ИЗМЕНИТЬ

Хорошо, возможно, это проблема жизненного цикла. Только что понял, что все, что я установил в асинхронном блоке, равно нулю вне блока, по крайней мере, пока не стало слишком поздно, чтобы что-то изменить. Вот почему никогда не вызывается cellForRowAtIndexPath — потому что masterDataList, передаваемый в UITableView, пуст. Протестировано это путем инициализации

__block NSString *s = [[NSString alloc] init];

вне блока, затем установив значение внутри блока:

s = @"Testing...";

и, наконец, NSLogging значение s после предположительного запуска блока. Но очевидно, что блок еще не запущен, потому что s равно нулю.


person esvendsen    schedule 18.03.2012    source источник


Ответы (2)


Похоже, вы поступаете правильно, возвращаясь к основному потоку после завершения работы, но вы не сказали табличному представлению, что оно должно отображать новые данные. [self.tableView reloadData] должен помочь.

person rickster    schedule 19.03.2012
comment
Я попробовал это в ViewController, но, возможно, это было не в том месте. Будет ли это происходить в методе viewDidLoad, в методе cellForRowAtIndexPath или где-то еще? - person esvendsen; 19.03.2012
comment
+1 за подсказку reloadData. Хотя это не был полный ответ на мою проблему, он был определенно неотъемлемым. - person esvendsen; 27.03.2012

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

В результате я разделил свой код, поэтому я использовал класс DataController только для управления данными (я знаю, что это революционно) и переместил все части GCD в свой ViewController. Измененный код:

Класс DataController:

- (void)initializeDefaultDataList {
    NSMutableArray *dataList = [[NSMutableArray alloc] init];
    self.masterDataList = dataList;
}

Класс ViewController:

@interface ObjectMasterViewController () {
    __block NSString *jsonString;
}
@end

...

- (void)getJSONString
{
    jsonString = [JSONHelper JSONpostString:@"http://webservice/getData"];
}

...

- (void)initData {
    NSError *jsonError = nil;
    //convert string to dictionary using NSJSONSerialization
    NSDictionary *jsonResults = [NSJSONSerialization JSONObjectWithData: [jsonString dataUsingEncoding:NSUTF8StringEncoding] 
                                                                options: NSJSONReadingMutableContainers 
                                                                  error: &jsonError];
    if (jsonError) NSLog(@"[%@ %@] JSON error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), jsonError.localizedDescription);

    NSArray *dataArray = [jsonResults objectForKey:@"d"];
    //loop through array and add items to list
    for (NSString *dataItem in dataArray) {
        [self addDataWithItem:dataItem];
    }
}

...

- (void)viewDidLoad
{
    [super viewDidLoad];
    dispatch_queue_t myQueue = dispatch_queue_create("name.queue.my", NULL);
    dispatch_async(myQueue, ^{
        //initalize service url string
        [self getJSONString];
        dispatch_async(dispatch_get_main_queue(), ^{
            //retrieve data
            [self initData];
            //reload tableView with new data
            [self.tableView reloadData];
        });
    });
}

Надеюсь, это может помочь кому-то, кто может быть в той же лодке, в которой был я.

person esvendsen    schedule 27.03.2012