0

So here's the deal:

I am building an app that accesses the internal addressbook on the iPhone. Everything was working fine (and is working fine on the simulator still), but now on the device I get a ThreadBreak and lldb opens up with no error message in the console on this line:

tempPerson.firstname =  ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as String? ?? ""

Again, this is still working on the simulator mind you and used to work just fine.

There is some multithread action going on because I am loading the addressbook into memory in the background using GCD above:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {

My addressbook was loaded properly. I have deleted the app from my test device (iPhone 6), cleaned the project (figuring it could be a bad link between some Obj-C bridge file that didn't like the ABAddressBook datatype, and even hopped on one foot while holding the phone Northward for good luck. Nothing worked.

I just can't figure out why it would work on all the Simulators and not on the phone. I do, however, notice that the app is not asking permission to access the contacts when it firsts opens after deleting (though the Authorization check is called and is granting authorization):

case .Authorized:
        return  self.createAddressBook()

I'm at a loss at even what to show you all since it's not returning much of anything, but here is a breakdown of the Thread Error (NOTE: Sometimes it happens on different threads...)

Thread 4
Queue: com.apple.root.background.-qos (concurrent)

0 swift_getObjectType
1 swift_dynamicCast
2 SomeApp.ViewController.(createAddressBook(SomeApp.ViewController) -> () -> Swift.Bool).(closure #1)
3_Dispatch_call_block_and_release
4_dispatch_client_callout
5_dispatch_root_queue_drain
6_dispatch_worker_thread3
7_pthread_wqthread

Enqueued from com.apple.main-thread (Thread 1)

0_dispatch_async_f_slow
*>> 1_SomeApp.ViewController.createAddressBook(SomeApp.ViewController)() -> Swift.Bool [inlined]
2_SomeApp.ViewController.determineStatus(SomeApp.ViewController)() -> Swift.Bool
3_SomeApp.ViewController.loadContacts(SomeApp.ViewController() -> ()
4_SomeApp.ViewController.viewDidLoad(SomeApp.ViewController() -> ()

... etc Viewloading stuff

On the breakpoint, the two variables given in the debugger are

The addressbookref

 adbk = (AnyObject?) (instance_type = Builtin.RawPointer = 0x...     EvaluatingTo: Some

and the ViewController called "Self"

self(SomeApp.ViewController)

containing all the variables my app uses elsewhere.

Sorry for being so verbose, but I really don't know what of this is relevant and what isn't.. Thanks for your help in advance!

Update: I turned off multithreading/ dispatching and it didn't work. So it must be something to do with that tempPerson.firstname bit.

Update 2: It does go around the loop twice and get two contacts before failing. I think it is hitting a nil value that isn't quite nil for some of the contacts and then crashing.. I do have the following check for it though and it is passing through:

if ABRecordCopyValue(person, kABPersonFirstNameProperty).takeRetainedValue() as AnyObject? != nil{

&

 if ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue() as AnyObject? != nil{

respectively.

Update 3: Okay. So Now it seems whenever there is a blank field for first or last name it crashes (on the simulator now too). Which really sucks because I thought I put in a good check to make sure I am not accessing nil valued properties. Whats even more annoying is that I haven't changed this code and it was working fine until I removed some derived data and changed the test file to avoid a linker error. Anything that could happen in the build process that is mucking up my code?

  • 2
    "I am loading the addressbook into memory in the background" May one ask why on earth you are doing that? It could be the cause of the problem, and is utterly unnecessary. There is no need to be multithreaded in any way, shape, or form in dealing with the address book. See my sample code here: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch18p713addressBook/ch31p973addressBook/ViewController.swift Notice that I never do anything with threads except to get back on the _main_ thread in the authorization completion handler. – matt Dec 12 '14 at 20:05

1 Answers1

0

Basically, you need to really check your type casts when accessing the addressbook, see:

tempPerson.lastname = ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue() as NSObject as? String  ?? ""

The problem is that some people have really dirty addressbooks for a variety of reasons and even have some mixed up properties like having a last name property that contains "LastName, FirstName SPACE Birthday" with no firstname property.

For whatever reason, typecasting first as an NSObject BEFORE as a String seems to work well.