我有一个列表数组ALAsset URL。我想将该 URL 逐个转换为 ALAsset 并将其添加到新数组中。
这是我的代码:
-(void)retrieveAssetsWithArray:(NSArray *)assetsArray
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
__block NSMutableArray *retrievedAssetsArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [assetsArray count]; i++)
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[NSURL URLWithString:[assetsArray objectAtIndex:i]]
resultBlock:^(ALAsset *asset)
{
if (asset)
{
NSLog(@"assetss: %@", asset);
[retrievedAssetsArray addObject:asset];
NSLog(@"assets arayyyy: %@", retrievedAssetsArray);
}
}
failureBlock:^(NSError *error)
{
NSLog(@"Error: Cannot load asset - %@", [error localizedDescription]);
}
];
}
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
if ([self.delegate respondsToSelector:@selector(getRetrievedAssetsFromPhotoLibrary:)])
{
NSLog(@"retrievedAssetsArray :%@", retrievedAssetsArray);
[self.delegate getRetrievedAssetsFromPhotoLibrary:retrievedAssetsArray];
}
});
});
}
将 URL 转换为 ALAsset 的部分工作正常。但是当我尝试将其记录在dispatch_async(dispatch_get_main_queue()
中时,retrievedAssetsArray
会像这样返回:
retrievedAssetsArray :(
"ALAsset - Type:Unknown, URLs:(null)",
"ALAsset - Type:Unknown, URLs:(null)",
"ALAsset - Type:Unknown, URLs:(null)",
"ALAsset - Type:Unknown, URLs:(null)"
)
为什么会这样?任何人都可以告诉我如何解决这个问题?干杯。
我找到了问题的答案:
-(void)retrieveAssetsWithArray:(NSArray *)assetsArray
{
__block NSMutableArray *retrievedAssetsArray = [[NSMutableArray alloc] init];
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
for (NSString *string in assetsArray) {
dispatch_async(queue, ^{
[library assetForURL:[NSURL URLWithString:string] resultBlock:^(ALAsset *asset) {
[retrievedAssetsArray addObject:asset];
dispatch_semaphore_signal(sema);
} failureBlock:^(NSError *error) {
dispatch_semaphore_signal(sema);
}];
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
dispatch_release(sema);
/* Check out ALAssets and return in delegate methods*/
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
if ([self.delegate respondsToSelector:@selector(getRetrievedAssetsFromPhotoLibrary:)])
{
NSLog(@"retrieve %@", retrievedAssetsArray);
[self.delegate getRetrievedAssetsFromPhotoLibrary:retrievedAssetsArray];
}
});
}
你应该像那里一样做:
typedef void (^VoidBlock)(void);
-(void)retrieveAssetsWithArray:(NSArray *)assetsArray
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
__block NSMutableArray *retrievedAssetsArray = [[NSMutableArray alloc] init];
__block NSNumber *completCount = @0;
VoidBlock internalCompletionBlock = ^{
completCount = @(completCount.integerValue + 1);
if (completCount.integerValue != assetsArray.count)
return;
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
if ([self.delegate respondsToSelector:@selector(getRetrievedAssetsFromPhotoLibrary:)])
{
NSLog(@"retrievedAssetsArray :%@", retrievedAssetsArray);
[self.delegate getRetrievedAssetsFromPhotoLibrary:retrievedAssetsArray];
}
});
};
for (int i = 0; i < [assetsArray count]; i++)
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:[NSURL URLWithString:[assetsArray objectAtIndex:i]]
resultBlock:^(ALAsset *asset)
{
if (asset)
{
NSLog(@"assetss: %@", asset);
[retrievedAssetsArray addObject:asset];
NSLog(@"assets arayyyy: %@", retrievedAssetsArray);
}
internalCompletionBlock();
}
failureBlock:^(NSError *error)
{
internalCompletionBlock();
NSLog(@"Error: Cannot load asset - %@", [error localizedDescription]);
}
];
}
});
}
尽管 log 语句在任何结果块保证运行之前运行,但您的代码已经设法从外观上拉回了四个资产。
结果块是异步调用的,这意味着您可以在任何资产实际放入retrievedAssetArray
之前轻松退出 for 循环。 然后,在主队列上执行 NSLog。
您需要重构代码以计算结果块的执行次数,并在计数达到assetsArray
中的对象数时调度到主队列。 您需要在结果块内执行此检查。
作为问题的一部分,您必须在整个异步assetForURL:resultBlock:failureBlock:
期间保留ALAssetLibrary
。
因此,您可以考虑为 ALAssetLibrary 组织一个单一实例,例如:
static ALAssetsLibrary* library;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
});
主要问题是assetForURL:resultBlock:failureBlock:
是异步方法,因此您需要等到它完成执行,无论是通过调用resultBlock:
还是failureBlock:
。
您可以使用 dispatch_group
或 dispatch_semaphore
或一个简单的块来等待异步操作完成,该块减少异步操作的数量并在达到零时调用完成。