我使用快速枚举,在枚举块中,我异步发送网络请求。
所以会发生什么是enumerateObjectsUsingBlock:只需要超级快速调用块,让枚举块在一段时间后完成。
这会导致不同的结果,因为有些请求比其他请求完成得更快。所以它没有按我的意愿排序。
有没有办法将块设置为冻结,异步网络请求完成后,只是告诉它转到下一个?
这是一些代码
NSArray *sites = [self.fetchedResultsController.fetchedObjects copy];
NSLog(@"sites - %@",sites);
[sites enumerateObjectsUsingBlock:^(Sites *site, NSUInteger idx, BOOL *stop) {
NSLog(@"site name - %@,",site.name);
[[Wrapper sharedWrapper] sendRequestTo:site completionBlock:{
NSLog(@"site name - %@",site.name);
}];
}];
谢谢!
答案 0 :(得分:1)
我想实现同样的目的,但继续使用块来简化我的代码,而不是通过递归方法传递参数的麻烦。我想出了这个NSArray类别:
NS_ASSUME_NONNULL_BEGIN
@interface NSArray(MH)
- (void)mh_asyncEnumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL* stop, dispatch_block_t next))block;
@end
NS_ASSUME_NONNULL_END
@implementation NSArray(MH)
- (void)mh_asyncEnumerateObjectsUsingBlock:(void (^)(id _Nonnull obj, NSUInteger idx, BOOL* stop, dispatch_block_t next))block{
__block NSUInteger index = 0;
__block BOOL stop = NO;
void (^next)();
__block __weak typeof(next) weakNext;
weakNext = next = ^void() {
void (^strongNext)() = weakNext;
// check if finished
if(stop || index == self.count){
return;
}
id obj = self[index];
index++;
block(obj, index - 1, &stop, strongNext);
};
next();
}
@end
它的使用方式如下:
NSArray* a = @[@"Malc", @"Bob", @"Jim"];
[a mh_asyncEnumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *stop, dispatch_block_t next) {
// simulate an async network call
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", obj);
next();
});
}];
输出:
2016-01-04 22:41:04.631 Malc
2016-01-04 22:41:05.632 Bob
2016-01-04 22:41:06.720 Jim
如您所见,此演示以1秒的延迟输出数组中的每个字符串。您可以通过在块内进行网络调用来使用它,然后在完成后调用next。如果您遇到错误并想取消只设置* stop = YES;在调用next()之前,就像使用普通枚举一样。
NSArray *sites = [self.fetchedResultsController.fetchedObjects copy];
NSLog(@"sites - %@",sites);
[sites mh_asyncEnumerateObjectsUsingBlock:^(Site *site, NSUInteger idx, BOOL *stop, dispatch_block_t next){
NSLog(@"site name - %@,",site.name);
[[Wrapper sharedWrapper] sendRequestTo:site completionBlock:{
if(error){ // your completion block should have an error param!!!
*stop = YES;
}
NSLog(@"site name - %@",site.name);
next();
}];
}];
答案 1 :(得分:1)
有没有办法将块设置为冻结,之后 异步网络请求完成后,只需告诉它去 下一个?
NSArray *sites = [self.fetchedResultsController.fetchedObjects copy];
NSLog(@"sites - %@",sites);
[sites enumerateObjectsUsingBlock:^(Sites *site, NSUInteger idx, BOOL *stop) {
NSLog(@"site name - %@,",site.name);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[[Wrapper sharedWrapper] sendRequestTo:site completionBlock:{
NSLog(@"site name - %@",site.name);
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}];
^不是真正理想的方法,但是如果你想在等待异步请求完成之前同步迭代,那么上面将通过GCD完成。还有其他方法可以在异步任务完成后等待所有组离开时迭代和增加dispatch_group的位置,例如:
dispatch_group_t downloadGroup = dispatch_group_create();
dispatch_group_enter(downloadGroup);
[self fetchStuffInBackground:background withCompletion:^(NSArray *stuff, NSError *error) {
NSLog(@"leaving stuff");
dispatch_group_leave(downloadGroup);
}];
dispatch_group_enter(downloadGroup);
[self fetchAOtherStuffInBackground:background withCompletion:^(NSArray *stuff, NSError *error) {
NSLog(@"leaving other stuff");
dispatch_group_leave(downloadGroup);
}];
dispatch_group_enter(downloadGroup);
[self fetchLastStuffInBackground:background withCompletion:^(NSArray *lastStuff, NSError *error) {
NSLog(@"leaving last stuff");
dispatch_group_leave(downloadGroup);
}];
}
}
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
if (callback) {
callback(error);
}
});
答案 2 :(得分:0)
有没有办法将块设置为冻结,异步网络请求完成后,只是告诉它转到下一个?
您可以通过重新组织代码来实现该结果:而不是使用枚举,只需执行完成块中的异步请求,即:
- (void) doRequestAsync:(NSArray*)sites index:(NSUInteger)index {
if (index >= [sites count]) return;
NSString* site = [sites objectAtIndex:index];
[[Wrapper sharedWrapper] sendRequestTo:site completionBlock:{
NSLog(@"site name - %@",site.name);
[self doRequestAsync:sites index:++index];
}];
}
替代方法是修改您的Wrapper
类,使其使用异步网络(但在辅助线程上使用它,以避免阻止UI)。
或者您可以实施Async Completion Token pattern,以便在收到回复时对其进行重新排序。