从使用宏中央调度的单独DataController类填充ViewController类中的UITableView

时间:2012-03-18 22:15:33

标签: objective-c ios grand-central-dispatch

我在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是零。

2 个答案:

答案 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];
        });
    });
}

希望这可以帮助那些可能和我在同一条船上的人。