次のようなシリアル バックグラウンド キューを作成しています。
@property (nonatomic, strong) dispatch_queue_t assetCreationQueue;
// in init...
_assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);
次に、バックグラウンドで ALAsset オブジェクトを次のように列挙します。
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
dispatch_async(weakSelf.assetCreationQueue, ^{
ALAssetRepresentation *assetRepresentation = [asset defaultRepresentation];
NSURL *url = [assetRepresentation url];
if (url) {
AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
// This NSLog fires! avAsset exists.
NSLog(@"AVURLAsset %@", avAsset);
dispatch_async(dispatch_get_main_queue(), ^{
// This NSLog NEVER fires.
// Also tried dispatch_sync.
NSLog(@"add to assets array on main queue");
[weakSelf.assets insertObject:avAsset atIndex:0];
});
}
});
}
}];
assets 配列プロパティは次のように定義されます。
@property (nonatomic, strong) NSMutableArray *assets;
試してみると、コンソールにdispatch_sync(dispatch_get_main_queue(), ^{
1 つしか表示されず、デッドロックが発生していることを示しています。NSLog(@"AVURLAsset %@", avAsset);
dispatch_sync
しかし、どうすればその理由を知ることができますか? どこかわかりません。assetCreationQueue はバックグラウンド キューであり、メイン キューでのみ配列を操作する必要があります。
編集: これも失敗するはるかに単純化されたテストです:
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
if (asset){
dispatch_async(weakSelf.assetCreationQueue, ^{
if ([NSThread isMainThread]) {
NSLog(@"already main thread"); // gets called often!!
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"dispatch async on main queue"); // never gets called!!
});
}
});
}
}];
だから私が理解していないのは、dispatch_async(weakSelf.assetCreationQueue
. それは悪い結論につながるだけです:私が作成したキューはバックグラウンドキューではありません:
_assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);
なんで?