Reputation: 5217
I've struggled with this error hours, and finally I drill down to this piece of code. This code works well when you "Run" the app, but will cause app crashes when "Test". I've googled and found this question:
Occasional errors when running OCUnit application test suite on device
But the solution doesn't work for me ;-(
I am a newbie iOS developer, so I'm not sure if this piece of code does something evil. Can anybody tell me:
application:didFinishLaunchingWithOptions:
method?Thanks!
#import "BRAppDelegate.h"
#import <AssetsLibrary/AssetsLibrary.h>
@implementation BRAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
ALAssetsLibrary *lib = [ALAssetsLibrary new];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop){
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
}];
} failureBlock:^(NSError *error){
}];
});
return YES;
}
The strangest thing is that if I comment out
[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){
}];
No crash occurs!
Upvotes: 1
Views: 540
Reputation: 1318
I fixed this issue by clearing Xcode’s cache by deleting my DerivedData
folder.
rm -rf ~/Library/Developer/Xcode/DerivedData/
Upvotes: 1
Reputation: 50109
ALAssetLibrary isn't safe to run on any thread but the main thread. You use GCDD todispatch it to the background and therefore run in another thread.
read: http://death-mountain.com/2011/05/alassetslibrary-and-threads/
also take race to avoid mutating the asset library while enumerating it. that'd be bad too: Has anyone experienced crashes when using ALAssetsLibrary in a background thread?
you allocate it in a block.. a new one: but in a block so it goes away after the block is done because nobody else is holding on to it.
move the allocation of lib
into the main thread and save it as a member variable in the app delegate
so:
// Override point for customization after application launch.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
ALAssetsLibrary *lib = [ALAssetsLibrary new];
becomes:
@implementation AppDelegate {
ALAssetsLibrary *_lib;
}
...
// Override point for customization after application launch.
_lib = [ALAssetsLibrary new];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
Upvotes: 1