我在ViewController类中有一个UITableView。 ViewController类使用自定义dataController(在AppDelegate中指定)。在dataController类中,我从Web获取一些JSON,将其解析为NSMutableArray,然后使用该数据填充ViewController中的UITableView。
这一切都很有效,除了应用启动时有明显的延迟,因为需要时间来获取JSON并使用它。我想在加载此数据时显示带有活动指示符的空UITableView。不幸的是,每当我将dataController类中的代码放入调度队列时,UITableView永远不会填充数据(根据日志加载数据)。我只看到一张空白的桌子。
我想我的主要问题是我不知道如何在dataController类中设置队列,然后使用该队列中的数据更新UI,但是在另一个类中。
相关代码:
来自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的原因 - 因为传递给UITableView的masterDataList是空的。通过初始化
进行测试__block NSString *s = [[NSString alloc] init];
在块外,然后在块内设置一个值:
s = @"Testing...";
最后在块假定运行之后NSLogging s的值。但显然这个区块还没有运行,因为s是零。
答案 0 :(得分:1)
看起来你在工作完成后回到主线程上做了正确的事情,但是你还没有告诉表视图需要显示新数据。 [self.tableView reloadData]应该有所帮助。
答案 1 :(得分:1)
正如我在posts such as this one中发现的那样,异步调度中的数据集不能在队列外使用。据我了解,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];
});
});
}
希望这可以帮助那些可能和我在同一条船上的人。