2012-03-18 25 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