2016-12-03 54 views
1

我想從服務器獲取數據,並在for循環內進行多次調用。每次傳遞不同的參數。我知道這是可能的取像,我取下面的代碼數據:iOS從服務器內部獲取數據以進行循環

for (NSDictionary *feedItem in [feed objectForKey:@"content"]) { 
    // url with feedItem data. 
    NSURL *url = .... 
    [UrlMethod GetURL:url success:^(NSDictionary *placeData) { 
     if (placeData) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       // adding object to table data source array 
       [dataSourceArray addObject:[placeData objectForKey:@"data"]]; 
       // reloading table view. 
       [self.tableView reloadData]; 

       }); 
      } 
     } failure:^(NSError *error) { 

     }]; 
} 

的問題是,每當我將數據添加到dataSourceArry,它不添加順序。它根據API調用的響應進行添加。請讓我知道,如果不明確。

+0

那裏有很多SO帖子,你檢查過嗎? –

回答

1

在你的情況,我會先分配一個可變數組並在每個位置[NSNull空]:

NSInteger count = [[feed objectForKey:@"content"] count]; 
NSMutableArray *dataSourceArray = [NSMutableArray arrayWithCapacity:count]; 

for (NSInteger i = 0; i < count; ++i) { 
    [dataSourceArray addObject:[NSNull null]]; 
} 

然後,我會用一種叫做調度組(詳見這裏http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/):

__block NSError *apiCallError = nil; // Just to keep track if there was at least one API call error 
NSInteger index = 0; 

// Create the dispatch group 
dispatch_group_t serviceGroup = dispatch_group_create(); 

for (NSDictionary *feedItem in [feed objectForKey:@"content"]) { 

    // Start a new service call 
    dispatch_group_enter(serviceGroup); 

    // url with feedItem data. 
    NSURL *url = ... 

    [UrlMethod GetURL:url success:^(NSDictionary *placeData) { 
     if (placeData) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       // Add data to Data Source 
       // index should be the correct one, as the completion block will contain a snapshot of the corresponding value of index 
       dataSourceArray[index] = [placeData objectForKey:@"data"]; 
      } 

      dispatch_group_leave(serviceGroup); 
     } failure:^(NSError *error) { 
      apiCallError = error; 
      dispatch_group_leave(serviceGroup); 
     }]; 

    index++; 
} 

dispatch_group_notify(serviceGroup, dispatch_get_main_queue(),^{ 
    if (apiCallError) { 
     // Make sure the Data Source contains no [NSNull null] anymore 
     [dataSourceArray removeObjectIdenticalTo:[NSNull null]]; 
    } 

    // Reload Table View 
    [self.tableView reloadData]; 
}); 

希望它適合你。

+0

最後有人寫了更準確的答案:)感到難過我在計算我將是一個使用dispatch_group發佈代碼:)無論如何偉大的工作先生:)不知道這將被接受爲答案,但其100%準確:)完美使用dispatch_group :)因此投票:) –

+0

@SandeepBhandari謝謝! – ppalancica

+0

我可能會使用帶插槽號的NSDictionary代替鍵,因爲它可以讓您使用[字典計數]檢查狀態。 – dgatwood

1

這可能是對你的幫助,

//keep dictionary property which will store responses 
    NSMutableDictionary *storeResponses = [[NSMutableDictionary alloc]init]; 

    //Somewhere outside function keep count or for loop 
    NSInteger count = 0; 

    for (NSDictionary *feedItem in [feed objectForKey:@"content"]) { 
     //Find out index of feddItem 
     NSInteger indexOfFeedItem = [[feed objectForKey:@"content"] indexOfObject:feedItem]; 

     NSString *keyToStoreResponse = [NSString stringWithFormat:@"%d",indexOfFeedItem]; 

     // url with feedItem data. 
     NSURL *url = .... 
     [UrlMethod GetURL:url success:^(NSDictionary *placeData) { 
      if (placeData) { 
       //instead of storing directly to array like below 
       // adding object to table data source array 
       [dataSourceArray addObject:[placeData objectForKey:@"data"]]; 

       //follow this 
       //increase count 
       count++; 
       [storeResponses setObject:[placeData objectForKey:@"data"] forKey:keyToStoreResponse]; 


       // reloading table view. 
       if(count == [feed objectForKey:@"content"].count) 
       { 
        NSMutableArray *keys = [[storeResponses allKeys] mutableCopy]; //or AllKeys 
        //sort this array using sort descriptor 
        //after sorting "keys" 

        for (NSString *key in keys) 
        { 
         //add them serially 

         [dataSourceArray addObject:[storeResponses objectForKey:key]]; 
        } 

        dispatch_async(dispatch_get_main_queue(), ^{ 


         [self.tableView reloadData]; 



        }); 
       } 

      } 
     } failure:^(NSError *error) { 

     }]; 
    } 

編輯:我已經給這裏直接寫答案,而實際運行該代碼

+0

請不要只是發佈一堆代碼,沒有解釋。一個好的答案解釋了問題的原因,並解釋了答案如何解決問題。 – rmaddy

+0

@rmaddy感謝您的評論,但雨水知道什麼是問題,並且我在代碼中添加了很多評論,以幫助理解提議的解決方案。如果您仍然覺得需要編輯答案,可以繼續編輯我的答案或讓我知道你的感受,我會根據這個更新。 – sanman

0

這是因爲你可能面臨的編譯錯誤你正在異步地調用Web服務,所以它不能保證它會按照你的請求順序給出響應!

對於現在的解決方案:

  • 你應該寫你的api就像是在一個時間給予的所有數據。所以, 你不需要做很多網絡通話,它也會提高 的表現!
  • 第二件事你可以做遞歸式的功能,我的意思是從上一個completion handler發出另一個請求。在這種情況下,一旦你得到了迴應,那麼只有另一個請求將被初始化,但在這種情況下,你將不得不妥協與性能!所以根據我的第一個解決方案更好!
  • 另一件事您可以排序的數組後,你會得到所有的答覆,然後你可以重新載入你的tableView
+1

我也建議你採用這種方法。 –

+0

是啊....... :) @Dev_Tandel – Lion

0

嘗試以下操作: -

for (NSDictionary *feedItem in [feed objectForKey:@"content"]) { 
     // url with feedItem data. 
     NSURL *url = .... 
     [UrlMethod GetURL:url success:^(NSDictionary *placeData) { 
      if (placeData) { 

        // adding object to table data source array 
        [dataSourceArray addObject:[placeData objectForKey:@"data"]]; 
        // reloading table view. 
dispatch_sync(dispatch_get_main_queue(), ^{ 
        [self.tableView reloadData]; 
    }); 
        }); 

      } failure:^(NSError *error) { 

      }]; 
    } 
+1

UI操作應始終在主線程上。 – ppalancica

+0

@ppalancica謝謝! –

+0

這個答案應該如何解決這個問題?它實際上更糟。 – rmaddy

0

不要重裝在每次你的表循環。循環完成獲取數據後,對數據源數組進行排序以獲得所需的結果,然後重新加載表。