Alterplay / APAddressBook

Easy access to iOS address book
MIT License
1.38k stars 193 forks source link

Main thread gets blocked in 2nd init call #97

Closed mua closed 8 years ago

mua commented 8 years ago

Hello,

I can initialize and use first APAddressBook instance without problems, but whenever I do it again(after ABAddressBook gets out of scope), and create another instance, main thread gets blocked in [self.thread start] in init method.

I had no problems before iOS 9 SDK and latest APAddressBook library.

Thread 1Queue : com.apple.main-thread (serial)

0 0x0000000111b1951a in semaphore_wait_trap ()

1 0x000000011179f481 in _dispatch_semaphore_wait_slow ()

2 0x000000010cb2e97d in -[NSThread start]()

3 0x000000010bebd205 in -[APAddressBook init] at APAddressBook.m:35

4 0x000000010be1eae7 in -[cdContactsViewController loadContacts:fail:] at cdContactsViewController.m:142

5 0x000000010bdbe8e7 in -[cdEditRbtViewController contacts:] at cdEditRbtViewController.m:413

6 0x000000010d9db1fa in -[UIApplication sendAction:to:from:forEvent:]()

7 0x000000010db3f504 in -[UIControl sendAction:to:forEvent:]()

8 0x000000010db3f7d0 in -[UIControl _sendActionsForEvents:withEvent:]()

9 0x000000010db3e906 in -[UIControl touchesEnded:withEvent:]()

10 0x000000010de8bca5 in _UIGestureRecognizerUpdate ()

11 0x000000010da45592 in -[UIWindow _sendGesturesForEvent:]()

12 0x000000010da46681 in -[UIWindow sendEvent:]()

13 0x000000010d9f8752 in -[UIApplication sendEvent:]()

14 0x000000010d9d3fcc in _UIApplicationHandleEventQueue ()

15 0x000000011031d0a1 in CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION ()

16 0x0000000110312fcc in __CFRunLoopDoSources0 ()

17 0x0000000110312483 in __CFRunLoopRun ()

18 0x0000000110311e98 in CFRunLoopRunSpecific ()

19 0x0000000111ed4ad2 in GSEventRunModal ()

20 0x000000010d9d9676 in UIApplicationMain ()

belkevich commented 8 years ago

Hello,

Could you provide code example, how to reproduce the bug?

mua commented 8 years ago

Hello,

Here is a project: https://www.dropbox.com/s/r5k8o28pocu7afk/aptest.zip?dl=0

just tap button twice


#import "ViewController.h"
#import <APAddressBook.h>
#import <APAddressBook/APContact.h>

@interface ViewController ()

@property IBOutlet UITextView* textView;
- (IBAction)load:(id)sender;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)load:(id)sender
{
    APAddressBook *addressBook = [[APAddressBook alloc] init];
    [addressBook loadContacts:^(NSArray *contacts, NSError *error)
     {
         // hide activity
         if (!error && contacts.count)
         {
             for (APContact* con in contacts) {
                 NSString* s = (con.firstName && con.lastName) ? [NSString stringWithFormat:@"%@ %@", con.firstName, con.lastName] : (con.firstName ? con.firstName : con.lastName);
                 NSLog(@"%@", s);
                 self.textView.text = [NSString stringWithFormat:@"%@\n%@", self.textView.text, s];
             }
         }
         else
         {
             //dlg.delegate = self;
         }
     }];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

'''
belkevich commented 8 years ago

That what I've found [NSThread start] blocks ?!?. And unfortunately I don't know solution for now. Try to make addressBook a view controller property, so you don't need to create it again.

belkevich commented 8 years ago

Would you mind if I post a link to your example to Apple's mail list?

mua commented 8 years ago

Sure Alexey, go ahead.

belkevich commented 8 years ago

Thank you. Please, don't remove project from dropbox.

belkevich commented 8 years ago

Also, how did you get the stack trace for this bug? My Xcode 7 shows nothing.

mua commented 8 years ago

Use Debug Menu / Pause, when it gets frozen.

belkevich commented 8 years ago

Apple engineers are pretty fun guys:

That API is deprecated in iOS9 anyway. If you don’t need to support iOS 8 or earlier, use the new Contacts API.

I hope not all of them like this one))

mua commented 8 years ago

I don't think they realize this is about [NSThread start] creating a semaphore block in main thread, not exactly about AdressBook API itself.

belkevich commented 8 years ago

Fortunately, there have been a good guy - Jens Alfke:

So, the problem actually begins before you create the second thread. If you look at all of the running threads, you’ll see the first thread you created (“Thread 6” on my simulator) locked up inside its dealloc method:

(lldb) bt

  • thread #6: tid = 0x7b7198, 0x0000000104b4ed92 libsystem_kernel.dylibsyscall_thread_switch + 10 frame #0: 0x0000000104b4ed92 libsystem_kernel.dylibsyscall_thread_switch + 10 frame #1: 0x0000000104b2ddaf libsystem_platform.dylib_OSSpinLockLockSlow + 65 frame #2: 0x00000001016dba56 Foundation_NSThreadGet0 + 87 frame #3: 0x00000001017d794d Foundation`-[NSThread cancel] + 29
    • frame #4: 0x000000010164d83b ThreadFail-[MyThread dealloc](self=0x00007fdcb8d328b0, _cmd="dealloc") + 43 at MyThread.m:15 frame #5: 0x0000000101b62afe libobjc.A.dylibobjc_object::sidetable_release(bool) + 232

Calling [self cancel] inside an NSThread’s dealloc method is a bad idea — first, it’s not necessary (if the thread’s being dealloced, it can’t be running anymore), and second, you’re trying to get the thread to do stuff while it’s in the middle of being torn down. That’s probably what’s causing the deadlock.

And since the lock that’s stuck looks like a shared one used by all NSThreads, you then get a “tar baby” effect where other NSThread operations also lock up as soon as they try to acquire that lock.

I'll release the fix today

belkevich commented 8 years ago

Fixed. Update to version 0.1.14

mua commented 8 years ago

Great belkevich, thanks.