objective-cautomatic-ref-countingtoll-free-bridging

ObjC casting a block with toll-free-bridged types


Is it possible to pass a block that takes Objective-C types which have Toll-free-bridged equivalents directly into a method expecting a block with the C-types?

Concrete example

I'm wrapping the AddressBook and Contacts APIs depending on availability, and the frameworks contain two methods that for all intents and purposes are identical. Consider the completion block parameter of:

CNContactStore's - (void)requestAccessForEntityType:(CNEntityType)entityType completionHandler:(void (^)(BOOL granted, NSError *error))completionHandler

and

AddressBook's void ABAddressBookRequestAccessWithCompletion ( ABAddressBookRef addressBook, void(^)(bool granted, CFErrorRef error) completion );

I have a block of type void (^)(BOOL granted, NSError *error) and it would be great if I could pass it to ABAddressBookRequestAccessWithCompletion(...). I know that I could wrap my 'objc' block inside a block which takes the 'C types' as parameters but it feels pointless to do so when the types are toll-free bridgable.

Concrete questions

Is there a way to cast an object of type void (^)(BOOL granted, NSError *error to type void(^)(bool granted, CFErrorRef error)? If we can, what is the syntax? What are the implications of ownership in an ARC environment?


Solution

  • Simply cast the block.

    As a very rough example:

    typedef void(^InternalBlock)(bool granted, CFErrorRef error);
    
    - (void)requestAccess:(void (^)(BOOL, NSError *))completion {
    
        if ([CNContactStore class]) {
            [contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:completion];
        } else {
            ABAddressBookRequestAccessWithCompletion(addressBook, (InternalBlock)completion);
        }
    
    }