Search code examples
iosobjective-cios7swift

Swift equivalent for (__bridge NSArray*)


I am attempting to get a list of contacts with a certain name using swift. I have the following code:

let owner = owners[indexPath.row];

var addressBook = ABAddressBookCreateWithOptions(nil, nil)
var addressBookRef: ABAddressBookRef = Unmanaged<NSObject>.fromOpaque(addressBook.toOpaque()).takeUnretainedValue()

let ownerName: NSString = owner["name"]! as NSString

let allContacts = ABAddressBookCopyPeopleWithName(addressBookRef, ownerName)

println("All Contacts: \(allContacts)")

Apparently, allContacts has a value of Swift.Unmanaged. I would expect allContacts to be an NSArray.

In the tutorial I'm following allContacts is bridged to NSArray by adding (__bridge NSArray*) to ABAddressBookCopyPeopleWithName(addressBookRef, ownerName).

What could be causing the issue?


Solution

    1. You're doing a lot more wrapping/unwrapping Unmanaged and Opaque types than necessary. Your line:

      var addressBookRef: ABAddressBookRef = Unmanaged<NSObject>.fromOpaque(addressBook.toOpaque()).takeUnretainedValue()
      

      is equivalent to:

      var addressBookRef = addressBook.takeUnretainedValue()
      

      (And besides, you should be using let unless you want to assign another value to that variable, which seems unlikely. The optimizer will thank you.)

    2. You shouldn't need to cast to Foundation types when passing parameters to AddressBook APIs, either... but I can't make ABAddressBookCopyPeopleWithName return a non-empty array in my testing, even with ObjC, so it's hard to say.

    3. If you just want to print the array, you need nothing more than this (using ABAddressBookCopyArrayOfAllPeople instead because of the above issue, but usage of the returned array is the same):

      let addressBook: ABAddressBook = 
          ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue()
      let allContacts =
          ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue()
      println("All Contacts: \(allContacts)")
      

      (Presumably sometime between getting the addressBook and using it you're either checking ABAddressBookGetAuthorizationStatus() or calling ABAddressBookRequestAccessWithCompletion, right?)

    4. If you want to work with the ABRecord values in the array, you'll need to do a bit of casting. CoreFoundation types bridged to Foundation types, and Foundation arrays are bridged to Swift arrays, but it doesn't bridge all the way from CF to Swift automagically.

      for contact in ((allContacts as NSArray) as [ABRecord]) {
          let name = ABRecordCopyCompositeName(contact).takeRetainedValue()
          println(name)
      }
      

      (I put parentheses in that for statement to show the hierarchy of operations, but you don't actually need them in your code.)