Reputation: 3454
I am using this Project from github, it is an image picker. I have had to make a very small change since ios7 to make the preview images from your albums show again but with that change now when you leave the picker and come back into it the photos selected (2/5) resets to 0/5 even though I have photos selected. How can I fix this?
The dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
seems to be taking forever to update the ui even with dispatch_async(dispatch_get_main_queue()
to reload the ui inside of it. When I comment out the dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
the pictures load instantly but other things get broken that depend on the queue.
here is the code snippet with the dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
I changed with the code i changed commented out
AGIPCAssetsController.m:
- (void)loadAssets
{
[self.assets removeAllObjects];
__ag_weak AGIPCAssetsController *weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
__strong AGIPCAssetsController *strongSelf = weakSelf;
@autoreleasepool {
[strongSelf.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result == nil)
{
return;
}
AGIPCGridItem *gridItem = [[AGIPCGridItem alloc] initWithImagePickerController:strongSelf.imagePickerController asset:result andDelegate:strongSelf];
if ( strongSelf.imagePickerController.selection != nil &&
[strongSelf.imagePickerController.selection containsObject:result])
{
gridItem.selected = YES;
}
[strongSelf.assets addObject:gridItem];
}];
}
dispatch_async(dispatch_get_main_queue(), ^{
[strongSelf reloadData];
});
});
[strongSelf reloadData];
}
Upvotes: 8
Views: 1574
Reputation: 8512
AGIPCGridItem
is subclass of UIView
. Don't work with UIKit objects on background thread.
Make sure you need the background thread and if you do, put only heavy tasks to background. Creating an UIView
should not be that case.
Also, it's not recommended to use PRIORITY_LOW
use simple PRIORITY_DEFAULT
.
Edit: If you are curious why it did work on iOS 6: That's implementation detail of UIKit. It still was wrong, but somehow did what you expected.
Upvotes: 6
Reputation: 4677
I highlighted iMartin's answer "AGIPCGridItem is subclass of UIView. Don't work with UIKit objects on background thread." He's got it.
I had a very similar issue when moving iOS6 to 7. I was dispatching an ALAssets request in a background thread. Once the fetch completed, I would construct the UIImageView, a UILabel, and a wrapper and then send this object to the main/foreground thread to be rendered. This worked fine on iOS6, but on 7 it was not draw for about 20 seconds. It would sometime draw after a UI event like a touch.
Fix was to fetch the ALAsset in the background, send that to the main thread where I created the image view, etc. Works like a charm now.
Upvotes: 0
Reputation: 21244
The global dispatch queue is a shared resource. DISPATCH_QUEUE_PRIORITY_LOW
tasks run after every other task in the queue at a higher priority has run. If the queue is getting a lot of blocks submitted with a higher priority, your DISPATCH_QUEUE_PRIORITY_LOW
task may not run for a very long time!
This is documented in the Concurreny Programming Guide as well as the libdispatch man pages
So, basically, other higher priority tasks are keeping things busy and your low priority task is not getting an opportunity to go.
Upvotes: 0
Reputation: 2446
I spent quite a bit of time with this code and I couldn't find a proper solution. Apparently the issue has come up on github, and a user offered a fix:
https://github.com/arturgrigor/AGImagePickerController/issues/19
But apparently he just removed all the blocks running in background, so I suppose that for a large amount of images the performance would be bad.
My hunch is that inside a dispatch_async block runs code that calls some UIKit function, and thus the behaviour is basically undefined.
For example it seems to me that the setAsset
function in AGIPGridItem.m is called inside the dispatch_async you posted. It is calling UImage, and although it's inside a lock, it should be still be executed on the background thread, while all the UIKit code should be executed on the main one.
UITableViewCell load images and reused cells
But even if I wrap the call inside a dispatch_async(dispatch_get_main_queue()...)
it doesn't work yet.
It seems that the call [view removeFromSuperview];
in setItems
in AGIPGridell.m is responsible somehow, but removing it has the side effect of creating a memory leak (unsurprisingly).
Upvotes: 0