I\'m relative new to iOS-Development and swift. But up to this point I was always able to help myself by some research on stackoverflow and several documentations and tutori
Maybe it's more than just answering to your question, but this is how I deal with the address book.
I've defined a custom operator:
infix operator >>> { associativity left }
func >>> <T, V> (lhs: T, rhs: T -> V) -> V {
return rhs(lhs)
}
allowing to chain multiple calls to functions in a more readable way, for instance:
funcA(funcB(param))
becomes
param >>> funcB >>> funcA
Then I use this function to convert an Unmanaged<T>
to a swift type:
func extractUnmanaged<T, V>(value: Unmanaged<T>?) -> V? {
if let value = value {
var innerValue: T? = value.takeRetainedValue()
if let innerValue: T = innerValue {
return innerValue as? V
}
}
return .None
}
and a counterpart working with CFArray
:
func extractUnmanaged(value: Unmanaged<CFArray>?) -> [AnyObject]? {
if let value = value {
var innerValue: CFArray? = value.takeRetainedValue()
if let innerValue: CFArray = innerValue {
return innerValue.__conversion()
}
}
return .None
}
and this is the code to open the address book, retrieve all contacts, and for each one read first name and organization (in the simulator firstName always has a value, whereas department doesn't, so it's good for testing):
let addressBook: ABRecordRef? = ABAddressBookCreateWithOptions(nil, nil) >>> extractUnmanaged
let results = ABAddressBookCopyArrayOfAllPeople(addressBook) >>> extractUnmanaged
if let results = results {
for result in results {
let firstName: String? = (result, kABPersonFirstNameProperty) >>> ABRecordCopyValue >>> extractUnmanaged
let organization: String? = (result, kABPersonOrganizationProperty) >>> ABRecordCopyValue >>> extractUnmanaged
println("\(firstName) - \(organization)")
}
}
Note that the println
statement prints the optional, so you'll see in the console Optional("David")
instead of just David
. Of course this is for demonstration only.
The function that answers to your question is extractUnmanaged
, which takes an optional unmanaged, unwrap it, retrieves the retained value as optional, unwrap it, and in the end attempts a cast to the target type, which is String
for the first name property. Type inferral takes care of figuring out what T and V are: T is the type wrapped in the Unmanaged
, V is the return type, which is known because specified when declaring the target variable let firstName: String? = ...
.
I presume you've already taken care of checking and asking the user for permission to access to the address book.
I got it through this function here:
func rawValueFromABRecordRef<T>(recordRef: ABRecordRef, forProperty property: ABPropertyID) -> T? {
var returnObject: T? = nil
if let rawValue: Unmanaged<AnyObject>? = ABRecordCopyValue(recordRef, property) {
if let unwrappedValue: AnyObject = rawValue?.takeRetainedValue() {
println("Passed: \(property)")
returnObject = unwrappedValue as? T
}
else {
println("Failed: \(property)")
}
}
return returnObject
}
You can use it in your property like this:
let contactFirstName: String = {
if let firstName: String = rawValueFromABRecordRef(recordRef, forProperty: kABPersonFirstNameProperty) {
return firstName
}
else {
return ""
}
}()
If I want the values associated with various properties, I use the following syntax:
let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String
let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String
Or you can use optional binding:
if let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String {
// use `first` here
}
if let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String {
// use `last` here
}
If you really want to return a non-optional, where missing value is a zero length string, you can use the ??
operator:
let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String ?? ""
let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String ?? ""