APAddressBook
APAddressBook copied to clipboard
Crash in APAddressBook.m on iPhone 6
- APAddressBook/Core (0.1.11)
- APAddressBook/Swift (0.1.11)
My app crashes running on my iPhone 6 with a large AddressBook but does not crash in the iOS 6 simulator with only a few entries in APAddressBook.m:117
peopleArrayRef = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
Because:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000003
Triggered by Thread: 6
Thread 6 name: Dispatch queue: com.apple.root.default-qos
Thread 6 Crashed:
0 libsqlite3.dylib 0x000000019749006c 0x197444000 + 311404
1 libsqlite3.dylib 0x00000001974900cc 0x197444000 + 311500
2 libsqlite3.dylib 0x000000019748110c 0x197444000 + 250124
3 libsqlite3.dylib 0x000000019747fdf4 sqlite3_step + 524
4 AppSupport 0x000000018b5e7728 CPSqliteStatementSendResults + 72
5 AppSupport 0x000000018b5ecd08 CPRecordStoreProcessRecordStatementWithPropertyIndices + 188
6 AppSupport 0x000000018b5ed084 CPRecordStoreProcessQueryWithBindBlock + 128
7 AppSupport 0x000000018b5ed150 CPRecordStoreCopyAllInstancesOfClassWhereWithBindBlock + 136
8 AddressBook 0x000000018454ea28 ABCCopyArrayOfAllPeopleInSourceWithSortOrdering + 156
9 APAddressBook 0x00000001002b77b8 __48-[APAddressBook loadContactsOnQueue:completion:]_block_invoke (APAddressBook.m:117)
10 AddressBook 0x00000001845a3194 __37-[ABTCC accessRequestWithCompletion:]_block_invoke + 44
11 libdispatch.dylib 0x000000019776d990 _dispatch_call_block_and_release + 20
12 libdispatch.dylib 0x000000019776d950 _dispatch_client_callout + 12
13 libdispatch.dylib 0x000000019777a77c _dispatch_root_queue_drain + 1844
14 libdispatch.dylib 0x000000019777bc48 _dispatch_worker_thread3 + 104
15 libsystem_pthread.dylib 0x000000019794d228 _pthread_wqthread + 812
16 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
When the debugger breaks on frame 9 above:
(lldb) po self.addressBook
<ABCAddressBook 0x144d0b970 [0x197dc0f50]>
(lldb) po self
<APAddressBook: 0x1700533e0>
I enabled NSZombies objects in my scheme and it did nothing, but i noticed another thread with exeactly the same stack frames, see threads 2 and 6 below:
Hardware Model: iPhone7,2
Process: ABC [2876]
Path: /private/var/mobile/Containers/Bundle/Application/8E7B40EE-A4C2-4E09-8303-501BA3CF2FCC/ABC.app/ABC
Identifier: com.king7532.abc.ABC
Version: 99 (0.65)
Code Type: ARM-64 (Native)
Parent Process: launchd [1]
Date/Time: 2015-07-14 11:13:33.753 -0400
Launch Time: 2015-07-14 11:13:30.530 -0400
OS Version: iOS 8.4 (12H143)
Report Version: 105
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000003
Triggered by Thread: 6
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0:
0 UIKit 0x000000018a006ba8 -[UIViewController _isDeallocating] + 0
1 libobjc.A.dylib 0x000000019710a4b8 -[NSObject allowsWeakReference] + 20
2 libobjc.A.dylib 0x00000001971037e4 weak_register_no_lock + 140
3 libobjc.A.dylib 0x00000001971082cc objc_storeWeak + 212
4 ABC 0x00000001000eb5bc -[ZLPeoplePickerViewController setDelegate:] (ZLPeoplePickerViewController.h:48)
5 ABC 0x00000001001445a0 ABC.ABCContactsViewController.showPeoplePickerController (ABC.ABCContactsViewController)() -> () (ABCContactsViewController.swift:53)
6 ABC 0x0000000100146004 ABC.ABCContactsViewController.accessGrantedForAddressBook (ABC.ABCContactsViewController)() -> () (ABCContactsViewController.swift:185)
7 ABC 0x00000001001457e0 ABC.ABCContactsViewController.checkAddressBookAccess (ABC.ABCContactsViewController)() -> () (ABCContactsViewController.swift:153)
8 ABC 0x000000010014441c ABC.ABCContactsViewController.viewDidAppear (ABC.ABCContactsViewController)(Swift.Bool) -> () (ABCContactsViewController.swift:45)
9 ABC 0x000000010014446c @objc ABC.ABCContactsViewController.viewDidAppear (ABC.ABCContactsViewController)(Swift.Bool) -> () (ABCContactsViewController.swift:0)
10 UIKit 0x0000000189eb3f50 -[UIViewController _setViewAppearState:isAnimating:] + 588
11 UIKit 0x0000000189eb44bc -[UIViewController _endAppearanceTransition:] + 340
12 UIKit 0x000000018a1def1c __97-[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:]_block_invoke749 + 32
13 UIKit 0x0000000189f20268 -[UIViewController _executeAfterAppearanceBlock] + 60
14 UIKit 0x0000000189f201d0 _applyBlockToCFArrayCopiedToStack + 352
15 UIKit 0x0000000189e906a4 _afterCACommitHandler + 572
16 CoreFoundation 0x00000001853dc2a0 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 28
17 CoreFoundation 0x00000001853d922c __CFRunLoopDoObservers + 356
18 CoreFoundation 0x00000001853d960c __CFRunLoopRun + 832
19 CoreFoundation 0x00000001853052d0 CFRunLoopRunSpecific + 392
20 GraphicsServices 0x000000018ed5b6f8 GSEventRunModal + 164
21 UIKit 0x0000000189f02f3c UIApplicationMain + 1484
22 ABC 0x000000010012d97c main (AppDelegate.swift:15)
23 libdyld.dylib 0x000000019779aa04 start + 0
Thread 1 name: Dispatch queue: com.apple.libdispatch-manager
Thread 1:
0 libsystem_kernel.dylib 0x0000000197898c24 kevent64 + 8
1 libdispatch.dylib 0x000000019777de6c _dispatch_mgr_invoke + 272
2 libdispatch.dylib 0x000000019776f998 _dispatch_mgr_thread + 48
Thread 2 name: Dispatch queue: com.apple.root.default-qos
Thread 2:
0 libsqlite3.dylib 0x000000019748ffa4 0x197444000 + 311204
1 libsqlite3.dylib 0x000000019748110c 0x197444000 + 250124
2 libsqlite3.dylib 0x000000019748110c 0x197444000 + 250124
3 libsqlite3.dylib 0x000000019747fdf4 sqlite3_step + 524
4 AppSupport 0x000000018b5e7728 CPSqliteStatementSendResults + 72
5 AppSupport 0x000000018b5ecd08 CPRecordStoreProcessRecordStatementWithPropertyIndices + 188
6 AppSupport 0x000000018b5ed084 CPRecordStoreProcessQueryWithBindBlock + 128
7 AppSupport 0x000000018b5ed150 CPRecordStoreCopyAllInstancesOfClassWhereWithBindBlock + 136
8 AddressBook 0x000000018454ea28 ABCCopyArrayOfAllPeopleInSourceWithSortOrdering + 156
9 APAddressBook 0x00000001002b77b8 __48-[APAddressBook loadContactsOnQueue:completion:]_block_invoke (APAddressBook.m:117)
10 AddressBook 0x00000001845a3194 __37-[ABTCC accessRequestWithCompletion:]_block_invoke + 44
11 libdispatch.dylib 0x000000019776d990 _dispatch_call_block_and_release + 20
12 libdispatch.dylib 0x000000019776d950 _dispatch_client_callout + 12
13 libdispatch.dylib 0x000000019777a77c _dispatch_root_queue_drain + 1844
14 libdispatch.dylib 0x000000019777bc48 _dispatch_worker_thread3 + 104
15 libsystem_pthread.dylib 0x000000019794d228 _pthread_wqthread + 812
16 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
Thread 3:
0 libsystem_kernel.dylib 0x00000001978b3c78 __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x000000019794d2d8 _pthread_wqthread + 988
2 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
Thread 4:
0 libsystem_kernel.dylib 0x00000001978b3c78 __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x000000019794d2d8 _pthread_wqthread + 988
2 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
Thread 5:
0 libsystem_kernel.dylib 0x00000001978b3c78 __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x000000019794d2d8 _pthread_wqthread + 988
2 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
Thread 6 name: Dispatch queue: com.apple.root.default-qos
Thread 6 Crashed:
0 libsqlite3.dylib 0x000000019749006c 0x197444000 + 311404
1 libsqlite3.dylib 0x00000001974900cc 0x197444000 + 311500
2 libsqlite3.dylib 0x000000019748110c 0x197444000 + 250124
3 libsqlite3.dylib 0x000000019747fdf4 sqlite3_step + 524
4 AppSupport 0x000000018b5e7728 CPSqliteStatementSendResults + 72
5 AppSupport 0x000000018b5ecd08 CPRecordStoreProcessRecordStatementWithPropertyIndices + 188
6 AppSupport 0x000000018b5ed084 CPRecordStoreProcessQueryWithBindBlock + 128
7 AppSupport 0x000000018b5ed150 CPRecordStoreCopyAllInstancesOfClassWhereWithBindBlock + 136
8 AddressBook 0x000000018454ea28 ABCCopyArrayOfAllPeopleInSourceWithSortOrdering + 156
9 APAddressBook 0x00000001002b77b8 __48-[APAddressBook loadContactsOnQueue:completion:]_block_invoke (APAddressBook.m:117)
10 AddressBook 0x00000001845a3194 __37-[ABTCC accessRequestWithCompletion:]_block_invoke + 44
11 libdispatch.dylib 0x000000019776d990 _dispatch_call_block_and_release + 20
12 libdispatch.dylib 0x000000019776d950 _dispatch_client_callout + 12
13 libdispatch.dylib 0x000000019777a77c _dispatch_root_queue_drain + 1844
14 libdispatch.dylib 0x000000019777bc48 _dispatch_worker_thread3 + 104
15 libsystem_pthread.dylib 0x000000019794d228 _pthread_wqthread + 812
16 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
Thread 7:
0 libsystem_kernel.dylib 0x00000001978b3c78 __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x000000019794d2d8 _pthread_wqthread + 988
2 libsystem_pthread.dylib 0x000000019794ceec start_wqthread + 0
Any help will be greatly appreciated. Thanks
@belkevich Can you please look at this crash, since you modified it use a local queue instead of the main queue and I'm wondering if that has something to dot with it? I'm happy to help debug, thanks
Hi!
- Please, show the code of
APAddressBook
initialization and using. - Do you use
APAddressBook
in different threads/queues?
- I'm using ZLPeoplePickerViewController which init's and then loads the contacts in ZLAddressBook.m:
//
// ZLAddressBook.m
// ZLPeoplePickerViewControllerDemo
//
// Created by Zhixuan Lai on 11/11/14.
// Copyright (c) 2014 Zhixuan Lai. All rights reserved.
//
#import "ZLAddressBook.h"
#import "APAddressBook.h"
#import "APContact.h"
NSString *const ZLAddressBookDidChangeNotification =
@"ZLAddressBookDidChangeNotification";
@interface ZLAddressBook ()
@property (strong, nonatomic) APAddressBook *addressBook;
@property (strong, nonatomic, readwrite) NSArray *contacts;
@end
@implementation ZLAddressBook
+ (instancetype)sharedInstance {
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{ _sharedObject = [[self alloc] init]; });
return _sharedObject;
}
- (instancetype)init {
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.addressBook = [[APAddressBook alloc] init];
}
#pragma mark - APAddressBook
- (void)loadContacts:(void (^)(BOOL succeeded, NSError *error))completionBlock {
__weak __typeof(self) weakSelf = self;
self.addressBook.fieldsMask =
APContactFieldFirstName | APContactFieldLastName |
APContactFieldCompositeName | APContactFieldPhones |
APContactFieldThumbnail | APContactFieldRecordID |
APContactFieldEmails | APContactFieldAddresses;
self.addressBook.filterBlock = ^BOOL(APContact *contact) {
return contact.compositeName != nil;
};
[self.addressBook loadContacts:^(NSArray *contacts, NSError *error) {
if (!error) {
weakSelf.contacts = contacts;
if (completionBlock) {
completionBlock(YES, nil);
}
} else {
if (completionBlock) {
completionBlock(NO, error);
}
}
}];
[self.addressBook startObserveChangesWithCallback:^{
// [weakSelf reloadData];
[[NSNotificationCenter defaultCenter]
postNotificationName:ZLAddressBookDidChangeNotification
object:nil];
}];
}
@end
2nd point: No I am not using APAddressBook anywhere else in my app.
Ben
I figured out why my app was crashing, ZLPeoplePickerViewController was calling
(void)loadContacts:(void (^)(BOOL succeeded, NSError *error))completionBlock
above, twice during initialization of ZLPeoplePickerViewController which conversely was calling
APAddressBook loadContacts:^(NSArray *contacts, NSError *error)
again while it was already in the block and therefore the could not write to peopleArrayRef
again because of the __block
modifier?
__block CFArrayRef peopleArrayRef;
peopleArrayRef = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
If you're interested I can produce a sample app that will reproduce the problem?
Check out my branch:
https://github.com/king7532/ZLPeoplePickerViewController/tree/reproduce-APAddressBook-0-11-crash
of ZLPeoplePickerViewController and run the ZLPeopePickerViewControllerDemo xcodeworkspace to reproduce the crash (do not run pod install or update).
Also set a breakpoint in APAddressBook.m:112
and observe it being called twice and crashing after stepping thru the 2nd call on line 117.
Thank you! I'll check it out
How to reproduce the crash? Your example works fine on my device.
What device and how many contacts?
iPhone 4s, 133
This is definitely a race condition, because I also cannot reproduce it on my iPhone 6 simulator with just 6 contacts. But on my iPhone 6 (arm64) with 960 contacts it happens every time.
First time loadContact
method called from here
+ (void)initializeAddressBook {
[[ZLAddressBook sharedInstance] loadContacts:nil];
}
Looks like author wanted to preload all contacts and cache them. And your local address book is too heavy. And cache load doesn't get in time before you start load contacts again by pressing 'show people picker' button.
That's it.
So, how can I help you?))
Just jumping in here…I wanted to see if there is a solution to this crash, as our app has also experienced this crash as well.
My solution was to stop using APAddressBook and create my own AddressBookManager class encapsulating an AddressBookRef that I use throughout my app.
@djfitz I see 4 possible solutions:
- Just remove this "cache" code from
ZLPeoplePickerViewController
. Anyway it doesn't work when it really needs (on big address books). - Wrap
APAddressBook
calls to serial queue. - Use you own solution like @king7532
- Wait until we make
APAddressBook
thread safe.
A bit more information about pt. 4. It's not easy, because we can't use dispatch_queue
/NSOperationQueue
. Old Core Foundation functions doesn't work with them properly. See this issue. So we need to rewrite all addressBook
calls with NSThread
. Unfortunately I don't know when it will be done.
removing this helped for sure. its grabbing too many contacts all at once to be realistic.
+ (void)initializeAddressBook { [[ZLAddressBook sharedInstance] loadContacts:nil]; }
@ericlewis is right. All this contacts will use app memory for all time because it's singleton.
Didn't really notice a performance hit either when we removed it. So I certainly recommend. I'll also do a pull request against that FW so you don't have to mess with it.
It would be great! Thank you!
Can we expect this to be threadSafe any time soon?
For thread safe and concurrent Address Book operations take a look at https://github.com/danthorpe/Operations#addressbook
@king7532 NSOperation is wrapper on GCD. So, it doesn't have own runloop
. This solution doesn't fit us.
@spidergears I've found solution with NSThread
but it should be tested before I release it. I'm planning to finish this month.
Hello, New release '0.1.12' it thread safe. Check it. And if everything ok I close the issue