From d94dcdef0fd0b9f5b33a2c67343a5ca3f0ecafeb Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Mon, 5 Oct 2015 21:05:27 -0700 Subject: [PATCH] Only do PHAsset metadata requests one at a time to workaround Photos framework deadlock --- AsyncDisplayKit/ASMultiplexImageNode.mm | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASMultiplexImageNode.mm b/AsyncDisplayKit/ASMultiplexImageNode.mm index 3d26fc0610..7879970e3f 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.mm +++ b/AsyncDisplayKit/ASMultiplexImageNode.mm @@ -518,17 +518,33 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent ASDisplayNodeAssertNotNil(request, @"request is required"); ASDisplayNodeAssertNotNil(completionBlock, @"completionBlock is required"); + /* + * Locking rationale: + * As of iOS 9, Photos.framework will eventually deadlock if you hit it with concurrent fetch requests. rdar://22984886 + * Image requests are OK, but metadata requests aren't, so we limit ourselves to one at a time. + + * -[PHFetchResult dealloc] plays a role in this deadlock, so we help the fetch result die ASAP by never storing it. + */ + static NSLock *phRequestLock; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + phRequestLock = [NSLock new]; + }); + // This is sometimes called on main but there's no reason to stay there dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + // Get the PHAsset itself. - PHFetchResult *assetFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[request.assetIdentifier] options:nil]; - if ([assetFetchResult count] == 0) { + [phRequestLock lock]; + PHAsset *imageAsset = [PHAsset fetchAssetsWithLocalIdentifiers:@[request.assetIdentifier] options:nil].firstObject; + [phRequestLock unlock]; + + if (imageAsset == nil) { // Error. completionBlock(nil, nil); return; } - PHAsset *imageAsset = [assetFetchResult firstObject]; PHImageRequestOptions *options = [request.options copy]; // We don't support opportunistic delivery – one request, one image.