我正在创建一个这样的串行后台队列:
@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(), ^{
时,我只在控制台中获得一个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);
为什么?
答案 0 :(得分:3)
(不是真的答案,但我希望提供足够的信息以便继续前进。)
我尝试过一个非常简单的程序,这根本不会重现。我接到许多调用“在主队列上调度异步”并且没有调用“已经主线程”(与你期望的相反)。我在iPhone 5上运行它。完整代码:
#import "AppDelegate.h"
@import AssetsLibrary;
@interface AppDelegate ()
@property (nonatomic, strong) dispatch_queue_t assetCreationQueue;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.assetCreationQueue = dispatch_queue_create("com.mycompany.assetCreationQueue", DISPATCH_QUEUE_SERIAL);
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
AppDelegate __weak *weakSelf = self;
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[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!!
});
}
});
}
}];
}
failureBlock:nil];
return YES;
}
@end
请注意,在这里使用weakSelf
是不必要且危险的(但如果这是问题,那么你就会崩溃)。如果要将块存储在weakSelf
保留的对象的属性中,则只需self
。对于像这样的短寿命块,没有必要或甚至不需要。你使用它的方式,如果在枚举中间取消分配拥有对象(可以),weakSelf
将变为零,weakSelf.assetCreationQueue
将为nil
,{{{ 1}}会崩溃。 (但同样,这不太可能是你问题的原因,因为它应该崩溃。)