Re: Work with AddressBook without blocking the main thread
Yup, that’s my problem exactly. You explained it much better than I could! To be honest, I don’t have a real good reason for not using the main thread at the moment—it seems fine, performance-wise, for what I am doing. But I was interested in hearing if there was a more performant approach I might be missing, if only to satisfy my curiosity. Most of the info on the web about this is tons of GCD contortions that, from what I can tell, are missing the point. So with respect to spinning up a thread to “keep around”, just point me in the right direction here (this would be new stuff for me): is it NSThread I should look at? Appreciate it, Peter On Apr 25, 2015, at 8:33 PM, Quincey Morris quinceymor...@rivergatesoftware.com wrote: On Apr 25, 2015, at 17:06 , Peter Tomaselli peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com wrote: The crux of my problem is that, according to the docs, ABAddressBookRequestAccessWithCompletion’s completion handler “is called on an arbitrary queue”. However, ABAddressBookRequestAccessWithCompletion accepts as an argument an ABAddressBookRef that, presumably, has already been created. I’m not sure how to proceed here. GCD serial queues can guarantee serial access to stuff, but it doesn’t seem like they provide any guarantees about your code executing on any one thread in particular. So, it doesn’t seem like GCD helps me here. So you won’t be able to issue any AB… API calls from the completion handler directly. Instead, you’ll need to know which thread you created the ABAddressBookRef on, and arrange to issue the subsequent calls from there. This is easy if you created the ABAddressBookRef on the main thread, because the completion handler can use 'dispatch_async (dispatch_get_main_queue (), …’ to get back to the main thread. What you won’t be able to do is create the ABAddressBookRef via a block dispatched to some non-main GCD queue, because you won’t necessarily be able to return to the thread the queue was using at the time. In other words, if you need to create the ABAddressBookRef on a background thread for some reason, you’ll have to do it on a thread you create for yourself, and keep the thread around. But I wouldn’t expect you’d need to create the ABAddressBookRef anywhere but on the main thread, right? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Work with AddressBook without blocking the main thread
On Apr 25, 2015, at 17:54 , Peter Tomaselli peter.tomase...@icloud.com wrote: I don’t have a real good reason for not using the main thread at the moment—it seems fine, performance-wise, for what I am doing. The point of these restrictions on ABAddressBook is that it’s *already* an asynchronous API. There’s no synchronous waiting that would block the main thread, and the fact that the completion handler is called on an “arbitrary” thread suggests that all the heavy lifting is already done on a background thread, outside of your control. For that reason, I can’t think of a reason why you’d ever want to start from a background thread. Also, do you have a good reason for sticking with the C API? What about using the Cocoa API? [ABAddressBook sharedAddressBook] doesn’t seem to have the same-thread requirement, though [ABAddress addressBook] does. (Note that in the current state of OS X or iOS, it’s a mistake to assume that the C version of an API is more performant than the Obj-C version. It’s almost always better just to use the one that’s easier to use, and that’s almost always the Obj-C version.) But I was interested in hearing if there was a more performant approach I might be missing, if only to satisfy my curiosity. Most of the info on the web about this is tons of GCD contortions that, from what I can tell, are missing the point. So with respect to spinning up a thread to “keep around”, just point me in the right direction here (this would be new stuff for me): is it NSThread I should look at? https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html However, there’s no reason to believe that using a background thread is going to perform better. All you’d be moving to the background thread, I think, is the creation of the ABAddressBookRef data structure itself, which isn’t going to make any difference to anything. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Work with AddressBook without blocking the main thread
Hi there. I’m writing my first iPhone application and trying to figure out how to best work—asynchronously—with the AddressBook API. I’m building against iOS 8. I’m not experienced with Cocoa, but based on the docs, as well as seemingly-credible SO answers (particularly this one[0]), my understanding is that the ABAddressBook APIs are not only thread-unsafe but also thread… affine? Or whatever? In other words, it is not enough to access AddressBook objects in a serial fashion, they must actually be accessed from the same thread on which they were created. The crux of my problem is that, according to the docs, ABAddressBookRequestAccessWithCompletion’s completion handler “is called on an arbitrary queue”. However, ABAddressBookRequestAccessWithCompletion accepts as an argument an ABAddressBookRef that, presumably, has already been created. I’m not sure how to proceed here. GCD serial queues can guarantee serial access to stuff, but it doesn’t seem like they provide any guarantees about your code executing on any one thread in particular. So, it doesn’t seem like GCD helps me here. Finally, just to clarify my question a little: - I am interested in doing this “the right way”, and without any third-party libraries, as a learning experience. - I’d like to end up with a simple wrapper class that accepts blocks (I imagine) of the type void (^)(ABAddressBookRef) and executes them—abstracting away the authorization checking stuff, which I think I understand—without blocking the UI. Thanks for any suggestions! Peter [0] http://stackoverflow.com/a/10844781 ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Work with AddressBook without blocking the main thread
Thanks for the reply. Well, now you’ve got me doubting myself. This is for iOS. Isn’t the C API the only option on that platform? I am planning on doing some work with the address book that doesn’t seem to be directly supported in the API (basically, I want to display all the email addresses in the address book that meet certain criteria). For this, I was assuming I’d have to grab pretty much all the email addresses from the book and iterate through them, bucketing as I go. This is all in my head so far, but if my ABAddressBookRef must live on the main thread forevermore, doesn’t that mean my “filtering” code must also run on the main thread? This is the reason I am concerned about blocking. Instead, my hope was to build a small wrapper class for the ’book that would accept blocks, run them off away from the main thread, and call back to the UI when done. It sounds like that’s maybe what is available on OS X already? But this is an iPhone app. I’ll check out the threading stuff; sounds like that might be fun to try anyway. Appreciate the help, Peter On Apr 25, 2015, at 9:23 PM, Quincey Morris quinceymor...@rivergatesoftware.com wrote: On Apr 25, 2015, at 17:54 , Peter Tomaselli peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com wrote: I don’t have a real good reason for not using the main thread at the moment—it seems fine, performance-wise, for what I am doing. The point of these restrictions on ABAddressBook is that it’s *already* an asynchronous API. There’s no synchronous waiting that would block the main thread, and the fact that the completion handler is called on an “arbitrary” thread suggests that all the heavy lifting is already done on a background thread, outside of your control. For that reason, I can’t think of a reason why you’d ever want to start from a background thread. Also, do you have a good reason for sticking with the C API? What about using the Cocoa API? [ABAddressBook sharedAddressBook] doesn’t seem to have the same-thread requirement, though [ABAddress addressBook] does. (Note that in the current state of OS X or iOS, it’s a mistake to assume that the C version of an API is more performant than the Obj-C version. It’s almost always better just to use the one that’s easier to use, and that’s almost always the Obj-C version.) But I was interested in hearing if there was a more performant approach I might be missing, if only to satisfy my curiosity. Most of the info on the web about this is tons of GCD contortions that, from what I can tell, are missing the point. So with respect to spinning up a thread to “keep around”, just point me in the right direction here (this would be new stuff for me): is it NSThread I should look at? https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html However, there’s no reason to believe that using a background thread is going to perform better. All you’d be moving to the background thread, I think, is the creation of the ABAddressBookRef data structure itself, which isn’t going to make any difference to anything. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Work with AddressBook without blocking the main thread
On Apr 25, 2015, at 17:06 , Peter Tomaselli peter.tomase...@icloud.com wrote: The crux of my problem is that, according to the docs, ABAddressBookRequestAccessWithCompletion’s completion handler “is called on an arbitrary queue”. However, ABAddressBookRequestAccessWithCompletion accepts as an argument an ABAddressBookRef that, presumably, has already been created. I’m not sure how to proceed here. GCD serial queues can guarantee serial access to stuff, but it doesn’t seem like they provide any guarantees about your code executing on any one thread in particular. So, it doesn’t seem like GCD helps me here. So you won’t be able to issue any AB… API calls from the completion handler directly. Instead, you’ll need to know which thread you created the ABAddressBookRef on, and arrange to issue the subsequent calls from there. This is easy if you created the ABAddressBookRef on the main thread, because the completion handler can use 'dispatch_async (dispatch_get_main_queue (), …’ to get back to the main thread. What you won’t be able to do is create the ABAddressBookRef via a block dispatched to some non-main GCD queue, because you won’t necessarily be able to return to the thread the queue was using at the time. In other words, if you need to create the ABAddressBookRef on a background thread for some reason, you’ll have to do it on a thread you create for yourself, and keep the thread around. But I wouldn’t expect you’d need to create the ABAddressBookRef anywhere but on the main thread, right? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Work with AddressBook without blocking the main thread
Also, the post served to bring dispatch_get_current_queue() to my attention, which seems quite handy. Don’t get too excited on that score, it was deprecated 2 OS revisions ago despite there being some legitimate use cases for it. My bug report on that got closed with the “not changing it” response. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Work with AddressBook without blocking the main thread
On Apr 25, 2015, at 18:51 , Peter Tomaselli peter.tomase...@icloud.com wrote: This is for iOS. Isn’t the C API the only option on that platform? Yes, by the time I got there I didn’t notice that it was OS X only. I realize I was wrong, too, to call the address book API asynchronous. When you get down to searching for records, it does seem pretty synchronous. Under the circumstances, starting your own captive background thread for doing the bulk search seems like a good idea. On Apr 25, 2015, at 20:19 , Roland King r...@rols.org wrote: Also, the post served to bring dispatch_get_current_queue() to my attention, which seems quite handy. Don’t get too excited on that score, it was deprecated 2 OS revisions ago despite there being some legitimate use cases for it. My bug report on that got closed with the “not changing it” response. There was a discussion a while back, maybe here on this list, on the pitfalls of trying to get the current queue. An Apple engineer explained some of what can go wrong. It’s all terribly subtle, and the only safe answer is “don’t do this”. That was why I punted earlier, and just said you can’t do it. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Work with AddressBook without blocking the main thread
Ha, great link! It was fun reading about the possible pitfalls here. Database corruption simply by reading improperly? Yikes! Also, the post served to bring dispatch_get_current_queue() to my attention, which seems quite handy. This fella does not mention how he handles the whole “the [authorization request] completion handler is called on an arbitrary queue” issue, but probably the ‘solution’ there is for me to make a strategic retreat and prompt for access slightly before, instead of exactly at the moment that, I need access to the AB. Thanks for all the help, Quincey and Roland. I may still try this with a private thread and a runloop, just for fun. :) Peter On Apr 25, 2015, at 10:27 PM, Roland King r...@rols.org wrote: I had trouble believing there was an API left which was really thread-tied - until I convinced myself that this one really is. I wonder why, underlying SQL implementation perhaps? In the course of hunting around I found a blog entry here http://adrian.schoenig.me/blog/2012/05/05/ios-addressbook-framework-and-gcd/ http://adrian.schoenig.me/blog/2012/05/05/ios-addressbook-framework-and-gcd/. It ended with this update which is interesting if not authoritative After having had a chat with Apple engineers, the recommended way is the following: Create address book references on the fly whenever you need them. Do not bother keeping them around since they are lightweight and fast to create. The performance issue that I experienced was due to doing the initial search and the cache for the address book not yet being warmed up. You could just create a fake query at first to warm it up, but it is not recommended.” if you don’t need to keep a long-running persistent reference to the address book, you may well be able to create them when you need them, use them immediately and then throw them away again. You may be able to create lots of them in different blocks on possibly different background queues at the same time and effectively parallelise the whole thing. You could, again if you don’t just need one true ABAddressBookRef, squirrel created ones away in thread local storage, then they’re guaranteed to be per-thread, but I’d only even try that rather dubious solution if analysis showed that creating and destroying them was causing performance issues. On 26 Apr 2015, at 09:51, Peter Tomaselli peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com wrote: Thanks for the reply. Well, now you’ve got me doubting myself. This is for iOS. Isn’t the C API the only option on that platform? I am planning on doing some work with the address book that doesn’t seem to be directly supported in the API (basically, I want to display all the email addresses in the address book that meet certain criteria). For this, I was assuming I’d have to grab pretty much all the email addresses from the book and iterate through them, bucketing as I go. This is all in my head so far, but if my ABAddressBookRef must live on the main thread forevermore, doesn’t that mean my “filtering” code must also run on the main thread? This is the reason I am concerned about blocking. Instead, my hope was to build a small wrapper class for the ’book that would accept blocks, run them off away from the main thread, and call back to the UI when done. It sounds like that’s maybe what is available on OS X already? But this is an iPhone app. I’ll check out the threading stuff; sounds like that might be fun to try anyway. Appreciate the help, Peter On Apr 25, 2015, at 9:23 PM, Quincey Morris quinceymor...@rivergatesoftware.com mailto:quinceymor...@rivergatesoftware.com wrote: On Apr 25, 2015, at 17:54 , Peter Tomaselli peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com wrote: I don’t have a real good reason for not using the main thread at the moment—it seems fine, performance-wise, for what I am doing. The point of these restrictions on ABAddressBook is that it’s *already* an asynchronous API. There’s no synchronous waiting that would block the main thread, and the fact that the completion handler is called on an “arbitrary” thread suggests that all the heavy lifting is already done on a background thread, outside of your control. For that reason, I can’t think of a reason why you’d ever want to start from a background thread. Also, do you have a good reason for sticking with the C API? What about using the Cocoa API? [ABAddressBook sharedAddressBook] doesn’t seem to have the same-thread requirement, though [ABAddress addressBook] does. (Note that in the current state of OS X or iOS, it’s a mistake to assume that the C version of an API is more performant than the Obj-C version. It’s almost always better just to use the one that’s easier to use, and that’s almost always the Obj-C version.) But I was
Re: Work with AddressBook without blocking the main thread
I had trouble believing there was an API left which was really thread-tied - until I convinced myself that this one really is. I wonder why, underlying SQL implementation perhaps? In the course of hunting around I found a blog entry here http://adrian.schoenig.me/blog/2012/05/05/ios-addressbook-framework-and-gcd/ http://adrian.schoenig.me/blog/2012/05/05/ios-addressbook-framework-and-gcd/. It ended with this update which is interesting if not authoritative After having had a chat with Apple engineers, the recommended way is the following: Create address book references on the fly whenever you need them. Do not bother keeping them around since they are lightweight and fast to create. The performance issue that I experienced was due to doing the initial search and the cache for the address book not yet being warmed up. You could just create a fake query at first to warm it up, but it is not recommended.” if you don’t need to keep a long-running persistent reference to the address book, you may well be able to create them when you need them, use them immediately and then throw them away again. You may be able to create lots of them in different blocks on possibly different background queues at the same time and effectively parallelise the whole thing. You could, again if you don’t just need one true ABAddressBookRef, squirrel created ones away in thread local storage, then they’re guaranteed to be per-thread, but I’d only even try that rather dubious solution if analysis showed that creating and destroying them was causing performance issues. On 26 Apr 2015, at 09:51, Peter Tomaselli peter.tomase...@icloud.com wrote: Thanks for the reply. Well, now you’ve got me doubting myself. This is for iOS. Isn’t the C API the only option on that platform? I am planning on doing some work with the address book that doesn’t seem to be directly supported in the API (basically, I want to display all the email addresses in the address book that meet certain criteria). For this, I was assuming I’d have to grab pretty much all the email addresses from the book and iterate through them, bucketing as I go. This is all in my head so far, but if my ABAddressBookRef must live on the main thread forevermore, doesn’t that mean my “filtering” code must also run on the main thread? This is the reason I am concerned about blocking. Instead, my hope was to build a small wrapper class for the ’book that would accept blocks, run them off away from the main thread, and call back to the UI when done. It sounds like that’s maybe what is available on OS X already? But this is an iPhone app. I’ll check out the threading stuff; sounds like that might be fun to try anyway. Appreciate the help, Peter On Apr 25, 2015, at 9:23 PM, Quincey Morris quinceymor...@rivergatesoftware.com wrote: On Apr 25, 2015, at 17:54 , Peter Tomaselli peter.tomase...@icloud.com mailto:peter.tomase...@icloud.com wrote: I don’t have a real good reason for not using the main thread at the moment—it seems fine, performance-wise, for what I am doing. The point of these restrictions on ABAddressBook is that it’s *already* an asynchronous API. There’s no synchronous waiting that would block the main thread, and the fact that the completion handler is called on an “arbitrary” thread suggests that all the heavy lifting is already done on a background thread, outside of your control. For that reason, I can’t think of a reason why you’d ever want to start from a background thread. Also, do you have a good reason for sticking with the C API? What about using the Cocoa API? [ABAddressBook sharedAddressBook] doesn’t seem to have the same-thread requirement, though [ABAddress addressBook] does. (Note that in the current state of OS X or iOS, it’s a mistake to assume that the C version of an API is more performant than the Obj-C version. It’s almost always better just to use the one that’s easier to use, and that’s almost always the Obj-C version.) But I was interested in hearing if there was a more performant approach I might be missing, if only to satisfy my curiosity. Most of the info on the web about this is tons of GCD contortions that, from what I can tell, are missing the point. So with respect to spinning up a thread to “keep around”, just point me in the right direction here (this would be new stuff for me): is it NSThread I should look at? https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html However, there’s no reason to believe that using a background thread is going to perform better. All you’d be moving to the background thread, I think, is the creation of the ABAddressBookRef data structure itself, which isn’t going to make any