2012-03-18 27 views
0

我在ViewController类中有一个UITableView。 ViewController类使用自定义的dataController(在AppDelegate中指定)。在dataController类中,我从Web中获取一些JSON,将其解析为NSMutableArray,然后使用该数据在ViewController中填充UITableView。从独立的DataController类使用宏中央调度在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; 
} 

从视图控制器:

- (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是零。

回答

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

希望这可以帮助别人谁可能是在同一条船上我英寸

1

看起来你正在做正确的事情,在你的工作完成后回到主线程,但你还没有告诉它需要显示新数据的表视图。 [self.tableView reloadData]应该有所帮助。

+0

我想,在视图控制器,但它可能不在正确的位置。那会在viewDidLoad方法,cellForRowAtIndexPath方法或其他地方完成吗? – esvendsen 2012-03-19 00:19:14

+0

+1为reloadData提示。虽然这不是我的问题的完整答案,但它绝对是不可或缺的。 – esvendsen 2012-03-27 12:46:53