xiaowl
xiaowl

Reputation: 5217

App crashes when run unittest due to 'objc_getClassList returned more classes than it should have.'

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:

  1. Is it OK to do the job like in the application:didFinishLaunchingWithOptions: method?
  2. Why does this piece code throw the error?

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;
}

EDIT

The strangest thing is that if I comment out

[group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){

}];

No crash occurs!

Upvotes: 1

Views: 540

Answers (2)

user363349
user363349

Reputation: 1318

I fixed this issue by clearing Xcode’s cache by deleting my DerivedData folder.

rm -rf ~/Library/Developer/Xcode/DerivedData/

Upvotes: 1

Daij-Djan
Daij-Djan

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?


BUT the main problem is how you use the lib I think...

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

Related Questions