Заполните UITableView в классе ViewController из отдельного класса DataController, который использует централизованную диспетчеризацию - PullRequest
0 голосов
/ 19 марта 2012

У меня есть UITableView в классе ViewController. Класс ViewController использует пользовательский dataController (указанный в 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. Любая помощь или советы, которые вы можете дать, будут с благодарностью. Я даже не уверен, правильно ли я выражаю свой вопрос - просто кажется, что то, что я хочу сделать, не должно быть таким сложным. Спасибо!

EDIT

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

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

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

s = @"Testing...";

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

Ответы [ 2 ]

1 голос
/ 27 марта 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];
        });
    });
}

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

1 голос
/ 19 марта 2012

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

...