2016-12-03 5 views
1

forループ内で複数の呼び出しを使用してサーバーからデータをフェッチします。私は毎回異なるパラメータを渡しています。私はdataSourceArryにデータを追加するたびに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) { 

     }]; 
} 

問題は、ある、それは順次追加されていません。私は私は以下のコードで取り出してるようなデータを取得することが可能である知っています。 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を使ってコードを投稿する人になるだろう:)とにかく偉大な職人:)確かにこれは答えとして受け入れられるだろうが、 dispatch_groupの使用:)従って投票: –

+0

@SandeepBhandariありがとう! – ppalancica

+0

私はおそらくスロット番号をキーとして代わりにNSDictionaryを使用します。これは、[dict count]でステータスをチェックできるためです。 – 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を記述する必要があります。だから、 あなたは多くのネットワークを呼び出す必要はありませんし、 パフォーマンスも向上します!
  • 再帰的な種類の関数を作成することができる第2のことは、前の1つの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

あなたのテーブル毎時間内をリロードしないでくださいループ。ループがデータの取得を終了したら、datasource配列のソートを行い、目的の結果を取得してからテーブルをリロードします。

関連する問題