我有以下代码加载一组图像,并在完成加载后通过completionHandler通知我。但是,我发现某些dispatch_group_leave有时不会被调用,我的猜测是在块运行之前取消分配imageLoader。如果我在loadImageWithURL:completionHandler块中放入了imageLoader的引用,那么一切都按预期工作。
我对原因的猜测是否正确?这个问题的正确解决方法是什么?我知道ARC在大多数情况下会自动阻止复制,在这种情况下我应该进行块复制吗?
- (void)loadGroupImagesAsyncWithCompletion:(void(^)(NSError *))completionHandler {
dispatch_group_t group = dispatch_group_create();
int index = 0;
for (Item *item in items) {
char queueLabel[30] = {0};
sprintf(queueLabel, "loader%d", index);
dispatch_queue_t queue = dispatch_queue_create(queueLabel, NULL);
dispatch_group_enter(group);
dispatch_async(queue, ^{
ImageLoader *imageLoader = [[ImageLoader alloc] init];
[imageLoader loadImageWithURL:url completionHandler:^(UIImage *image, NSError *error) {
if (image) {
item.image = image;
}
//NOTE: if item object is referenced in this block,
//then there is no missed dispatch_group_leave call.
dispatch_group_leave(group);
}];
});
}
// Non-blocking wait
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// shouldn't take more than 5 secs to load all images
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)));
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(nil);
});
});
}
答案 0 :(得分:0)
这是我的猜测。这只是猜测,因为您还没有发布与ImageLoader有关的代码。
如果-loadImageWithURL:completionHandler:
以异步方式运行,即它使用异步调度队列本身,那么在加载完成之前它被释放可能是正确的。这是因为它的生命周期只是声明它的for块的范围。
实际上,没有理由为什么该方法需要异步执行,因为您已经在异步块中获取了它。只需一个同步方法,并在方法完成后调用dispatch_group_leave()
。
修改强>
鉴于您无法控制ImageLoader并且-loadImageWithURL:completionHandler:
在没有任何帮助的情况下异步操作,您应该删除呼叫周围的dispatch_async
包装器。您仍然会遇到释放ImageLoader的问题,但可以通过在创建时将每个ImageLoader放入数组中来避免这种情况。
代码看起来像这样:
- (void)loadGroupImagesAsyncWithCompletion:(void(^)(NSError *))completionHandler
{
NSMutableArray* loaders = [[NSMutableArray alloc] init];
dispatch_group_t group = dispatch_group_create();
int index = 0;
for (Item *item in items) {
char queueLabel[30] = {0};
sprintf(queueLabel, "loader%d", index);
dispatch_queue_t queue = dispatch_queue_create(queueLabel, NULL);
dispatch_group_enter(group);
ImageLoader *imageLoader = [[ImageLoader alloc] init];
[imageLoader loadImageWithURL:url completionHandler:^(UIImage *image, NSError *error) {
if (image) {
item.image = image;
}
//NOTE: if item object is referenced in this block,
//then there is no missed dispatch_group_leave call.
dispatch_group_leave(group);
}];
[loaders addObject: imageLoader];
}
// Non-blocking wait
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// shouldn't take more than 5 secs to load all images
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)));
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(nil);
});
[loaders removeAllObjects];
});
}