У меня есть 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 был ноль.