Ios AlassetLibrary assetForURL方法的同步问题
从Ios AlassetLibrary assetForURL方法的同步问题,ios,objective-c,synchronization,alassetslibrary,Ios,Objective C,Synchronization,Alassetslibrary,从ALAssetsLibrary加载资产时出现一些同步问题 事实上,我正在尝试的是从摄影机滚动加载一些图片,这些图片的URL由一些数据库查询提供。现在,从数据库获取URL后,我使用assetForURL方法加载图片,加载图片后,我将图片显示到某个视图。因此,我在每次查询结果集返回记录时执行的循环中调用该方法。直到现在一切都很顺利。下面是演示该过程的示例代码: ALAssetsLibrary* library = [ALAssetsLibrary new]; //dispatch_group_t
ALAssetsLibrary
加载资产时出现一些同步问题
事实上,我正在尝试的是从摄影机滚动加载一些图片,这些图片的URL由一些数据库查询提供。现在,从数据库获取URL后,我使用assetForURL
方法加载图片,加载图片后,我将图片显示到某个视图。因此,我在每次查询结果集返回记录时执行的循环中调用该方法。直到现在一切都很顺利。下面是演示该过程的示例代码:
ALAssetsLibrary* library = [ALAssetsLibrary new];
//dispatch_group_t queueGroup = dispatch_group_create();
while ([rs next]) {
//some data load up
//load thumbnails of available images
[library assetForURL:url resultBlock:^(ALAsset *asset) {
UIImage* img = [[UIImage imageWithCGImage:asset.aspectRatioThumbnail] retain];
//dispatch_group_async(queueGroup, dispatch_get_main_queue(), ^{
//create views and add to container view
CGFloat left = (8.0f + dimension) * i + 8.0f;
CGRect rect = CGRectMake(left, 8.0f, dimension, dimension);
TileView* tileView = [[NSBundle mainBundle] loadNibNamed:@"TileView" owner:nil options:nil][0];
[tileView setFrame:rect];
tileView.tag = i;
tileView.active = NO;
[self.thumbnailContainer addSubview:tileView];
//display image in tileView, etc.
//.............
if (img) {
[img release];
}
NSLog(@"block %d: %d",i,[self.thumbnailContainer.subviews count]);
//});
} failureBlock:^(NSError *error) {
NSLog(@"failed to load image");
}];
i++;
}
NSLog(@"outside block %d",[self.thumbnailContainer.subviews count]);
[library release];
在我的代码中,thumbnailContainer是一个UIScrollView,在它里面我添加了自定义视图来显示缩略图图像,它可以正常工作
当我试图选择添加到self.thumbnailContainer
中的最后一个视图时,真正的困境出现了。我找不到任何方法来确定assetForURL
方法的所有异步块何时完成,以便self.thumbnailContainer
实际上包含一些子视图。因此,如果我在循环完成后立即记录self.thumbnailContainer
的子视图计数,它将显示0。在那之后,我发现所有的块代码都被执行,子视图的数量也在增加。这是很正常的行为,但与我的要求相矛盾。我尝试过GCD的dispatch\u group\u
和dispatch\u wait
方法,但没有成功
任何人都可以建议一种解决方法或替代编码模式来克服这种情况。任何帮助都将不胜感激。谢谢。有两种方法可以解决此问题。是的 1.NSLock。特别是NSConditionLock。基本上,您创建了一个条件为“挂起的任务”的锁。然后在assetForURL的完成和错误块中,使用“全部完成”条件将其解锁。这样,在调用assetForURL之后,只需使用“all complete”标识符调用lockWhenCondition,就完成了(它将等待块设置该条件) 2.在
resultBlock
和failureBlock
注意:
关于ALAsset库的性能,我已经提到了一些重要的事情。有两种方法可以解决这个问题。是的 1.NSLock。特别是NSConditionLock。基本上,您创建了一个条件为“挂起的任务”的锁。然后在assetForURL的完成和错误块中,使用“全部完成”条件将其解锁。这样,在调用assetForURL之后,只需使用“all complete”标识符调用lockWhenCondition,就完成了(它将等待块设置该条件) 2.在
resultBlock
和failureBlock
注意:
关于ALAsset库的性能,我已经提到了几件重要的事情。您可以使用调度组,正如您可能想到的那样:
- (void) loadViewsWithCompletion:(completion_t)completionHandler {
ALAssetsLibrary* library = [ALAssetsLibrary new];
dispatch_group_t group = dispatch_group_create();
while ([rs next]) {
dispatch_group_enter(group);
[library assetForURL:url resultBlock:^(ALAsset *asset) {
UIImage* img = [[UIImage imageWithCGImage:asset.aspectRatioThumbnail] retain];
dispatch_async(dispatch_get_main_queue(), ^{
//create views and add to container view
...
dispatch_group_leave(group);
});
} failureBlock:^(NSError *error) {
NSLog(@"failed to load image");
dispatch_group_leave(group);
}];
i++;
}
[library release];
if (completionHandler) {
dispatch_group_notify(group, ^{
completionHandler(someResult);
});
}
... release dispatch group if not ARC
}
但代码可能存在潜在问题:
由于异步加载图像,因此它们可能全部并行加载。这可能会消耗大量的系统资源。如果是这种情况,这取决于资产加载程序方法的实现assetForURL:resultBlock:failureBlock:
,则需要序列化循环
注意:方法assetForURL:resultBlock:failureBlock:
可能已经确保对资产库的访问被序列化。如果完成块的执行上下文也是串行队列,[UIImage imageWithCGImage:asset.aspectRatioThumbnail]
将串行执行。在这种情况下,您的循环只是将多个任务排队,但一次只处理一个映像,这样您就安全了
否则,如果方法
assetForURL:resultBlock:failureBlock:
并行运行,和/或块执行并发队列,则可能并行加载和处理图像。如果这些图像很大,这可能是一件坏事。您可能会利用调度组,正如您可能想到的:
- (void) loadViewsWithCompletion:(completion_t)completionHandler {
ALAssetsLibrary* library = [ALAssetsLibrary new];
dispatch_group_t group = dispatch_group_create();
while ([rs next]) {
dispatch_group_enter(group);
[library assetForURL:url resultBlock:^(ALAsset *asset) {
UIImage* img = [[UIImage imageWithCGImage:asset.aspectRatioThumbnail] retain];
dispatch_async(dispatch_get_main_queue(), ^{
//create views and add to container view
...
dispatch_group_leave(group);
});
} failureBlock:^(NSError *error) {
NSLog(@"failed to load image");
dispatch_group_leave(group);
}];
i++;
}
[library release];
if (completionHandler) {
dispatch_group_notify(group, ^{
completionHandler(someResult);
});
}
... release dispatch group if not ARC
}
但代码可能存在潜在问题:
由于异步加载图像,因此它们可能全部并行加载。这可能会消耗大量的系统资源。如果是这种情况,这取决于资产加载程序方法的实现assetForURL:resultBlock:failureBlock:
,则需要序列化循环
注意:方法assetForURL:resultBlock:failureBlock:
可能已经确保对资产库的访问被序列化。如果完成块的执行上下文也是串行队列,[UIImage imageWithCGImage:asset.aspectRatioThumbnail]
将串行执行。在这种情况下,您的循环只是将多个任务排队,但一次只处理一个映像,这样您就安全了
否则,如果方法
assetForURL:resultBlock:failureBlock:
并行运行,和/或块执行并发队列,则可能并行加载和处理图像。如果这些图像太大,这可能是一件坏事。谢谢您的回复。但是,我同意您的回答中的一个命题,即assetForURL
块在单独的线程上工作。在我自己的应用程序中,我发现这些块在主线程本身上工作,但是,这些块异步排队到主队列,也就是说,当成功加载资产时,resultBlock
在主队列中排队。资产加载过程本身仍然在某些不同的线程上工作。我会尽力处理你的NSConditionLock
建议,然后回来。再次感谢。不过,请使用dispatch_async(dispatch_get_main_queue())并在ui部分感受不同之处。感谢您的回复。不过,我还是同意一位专业人士的说法