2016-12-03 59 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

不要重装在每次你的表循环。循环完成获取数据后,对数据源数组进行排序以获得所需的结果,然后重新加载表。