aryaxt / OCMapper

Objective-C library to easily map NSDictionary to model objects, works perfectly with Alamofire. ObjectMapper works similar to GSON
MIT License
347 stars 45 forks source link

ObjectMapper init crashes when running on background thread #22

Closed hypherion2 closed 9 years ago

hypherion2 commented 9 years ago

When ObjectMapper is initialized in a background thread using GCD (i.e. dispatch_async), an EXC_BAD_ACCESS is thrown sometimes with the following call stack:

1 0x69290f9 StartWebThread() 2 0x2aad6b0 pthread_once_handler 3 0x2a9eebe _os_once 4 0x2aad65f pthreadonce 5 0x6928e8e WebThreadEnable 6 0x57fd32a +[WebView(WebPrivate) enableWebThread] 7 0x57fa090 WebKitInitialize 8 0x739330 UIApplicationLoadWebKit_block_invoke 9 0x2752bef _dispatch_client_callout 10 0x273ca92 dispatch_once_f 11 0x273c922 dispatch_once 12 0x739240 _UIApplicationLoadWebKit 13 0x1e31461 _class_initialize 14 0x1e39fe5 lookUpImpOrForward 15 0x1e39e8d _class_lookupMethodAndLoadCache3 16 0x1e4412f objc_msgSend 17 0x1e2f597 _class_resolveMethod 18 0x1e3a018 lookUpImpOrForward 19 0x1e39e41 lookUpImpOrNil 20 0x1e2f94c class_respondsToSelector 21 0x19d8163 +[NSBundle bundleForClass:] 22 0x190d2e6 -[ObjectMapper populateClassNamesFromMainBundle] 23 0x190ca1d -[ObjectMapper init] ... 27 0x27305ea _dispatch_call_block_and_release 28 0x2752bef _dispatch_client_callout 29 0x273a1ef _dispatch_root_queue_drain 30 0x273bb70 _dispatch_worker_thread3 31 0x2aae1da _pthread_wqthread

The offending line is: if ([NSBundle bundleForClass:class] == [NSBundle mainBundle]) in populateClassNamesFromMainBunde where class is sometimes_UICompatibilityTextView or UIWebDocumentView or others (varies on each occurrence). It seems to be classes related to WebKit. This is Xcode 6.2 although it happens on 6.1 as well with iOS 8.1 target.

aryaxt commented 9 years ago

Can you post some code? It seems to be working for me. This test passes

- (void)test
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        ObjectMapper *aMapper = [[ObjectMapper alloc] init];
        XCTAssertNotNil(aMapper);
    });
}
aryaxt commented 9 years ago

Aaah nvm it crashes outside of test environment, will look into it

aryaxt commented 9 years ago

This would fix the issue, but I don't think it's an ideal solution, will look for alternatives

NSString *className = NSStringFromClass(class);

if (![className hasPrefix:@"UI"] && ![className hasPrefix:@"_UI"] && [NSBundle bundleForClass:class] == [NSBundle mainBundle])
                    [self.classNamesInMainBundle addObject:className];
aryaxt commented 9 years ago

This is fixed, merged and pushed to cocoapods v1.8 The code that was looping through classes no longer exists, so you no longer need to initialize ObjectMapper on a background thread.