Get value as swift type from Unmanaged<AnyObject> . For example: ABRecordRef
Asked Answered
Y

2

30

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.

Yuu answered 22/9, 2014 at 23:56 Comment(0)
Y
56

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
Yuu answered 23/9, 2014 at 1:52 Comment(1)
If you are working in swift in a project that is not yet fully arc compliant, it is better to takeUnretainedValue(), otherwise you might create yourself an unintentional memory leak and zombies.Palestrina
M
1
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)")
            }
        }
    }
}

}

Madelle answered 10/3, 2015 at 22:40 Comment(1)
Welcome to Stack Overflow! Answers are most useful when they contain an explanation of your solution to the question's problem. Would you consider editing your post to add some more detail?Lyman

© 2022 - 2024 — McMap. All rights reserved.