Reputation: 53112
How do I get a value as a Swift type from an object of type Unmanaged<AnyObject>
. My example is using an ABRecordRef
I'm creating a contact object to manage once I get the ABRecordRef
, but I'm having trouble translating from ObjC. Here's what I have:
init(recordRef: ABRecordRef) {
if let firstName = ABRecordCopyValue(recordRef, kABPersonFirstNameProperty) {
self.firstName = firstName
}
}
If it were ObjC, I would do:
CFTypeRef firstNameRef = ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);
if (firstNameRef) {
self.firstName = (__bridge NSString *)firstNameRef;
}
I can't seem to find the right combination of downcasting / conversion, so any help is appreciated.
Upvotes: 30
Views: 12633
Reputation: 182
import UIKit
import AddressBook
class ViewController: UIViewController {
lazy var addressBook: ABAddressBookRef = {
var error: Unmanaged<CFError>?
return ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue() as ABAddressBookRef
}()
@IBAction func GetPeople(sender: UIButton) {
var ab: ABAddressBookRef = addressBook
switch ABAddressBookGetAuthorizationStatus(){
case .Authorized:
println("Authorized")
readFromAddressBook(addressBook)
case .Denied:
println("Denied")
case .Restricted:
println("Restricted")
case .NotDetermined:
println("Not determined")
ABAddressBookRequestAccessWithCompletion(addressBook,
{[weak self] (granted: Bool, error: CFError!) in
if granted {
let strongSelf = self!
println("Access is granted")
strongSelf.readFromAddressBook(strongSelf.addressBook)
}
else{
println("Access is not granted")
}
})
default:
break
}
}
func readFromAddressBook(addressBook: ABAddressBookRef){
let allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue() as NSArray
for person:ABRecordRef in allPeople{
if let firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty) {
if let lastName = ABRecordCopyValue(person, kABPersonLastNameProperty) {
let ln:String = (lastName.takeRetainedValue() as? String) ?? ""
let fn:String = (firstName.takeRetainedValue() as? String) ?? ""
println("\(ln) - \(fn)")
}
}
}
}
}
Upvotes: 1
Reputation: 53112
Since NoOne answered before I solved it, I'll add the answer here:
firstName.takeRetainedValue() as? String
If you look at the header of the Unmanaged
struct type, you'll find this:
/// Get the value of this unmanaged reference as a managed
/// reference and consume an unbalanced retain of it.
///
/// This is useful when a function returns an unmanaged reference
/// and you know that you're responsible for releasing the result.
func takeRetainedValue() -> T
So, because the CFTypeRef
is converted to Unmanaged<AnyObject>
in Swift.
Unmanaged
uses generics to define a return type, and it is declared like so:
Unmanaged<T>
Our object is of type Unmanaged<AnyObject>
which means that takeRetainedValue()
will return type T
, or in our case, type AnyObject
. I use optional downcasting since my property firstName
is of type String?
.
You can use the takeRetainedValue
method to get your value out of your Unmanaged
object. In Foundation API's, I'm guessing that they will mostly be of type Unmanaged<AnyObject>!
and a downcast will be required. The generic formula appears to be:
var unmanagedObject: Unmanaged<AnyObject> = someFunctionThatReturnsAnUnmanagedObject()
var newValue: Type = unmanagedObject.takeRetainedValue as Type
Upvotes: 56