我对iOS-Development和swift相对较新。但到目前为止,我总是能够通过对stackoverflow和一些文档和教程的一些研究来帮助自己。 但是,有一个问题我找不到任何解决方案。
我想从用户地址簿中获取一些数据(例如单值属性kABPersonFirstNameProperty
)。因为如果此联系人在地址簿中没有firstName值,.takeRetainedValue()
函数会抛出错误,我需要确保ABRecordCopyValue()
函数确实返回一个值。我试图在一个闭包中检查这个:
let contactFirstName: String = {
if (ABRecordCopyValue(self.contactReference, kABPersonFirstNameProperty) != nil) {
return ABRecordCopyValue(self.contactReference, kABPersonFirstNameProperty).takeRetainedValue() as String
} else {
return ""
}
}()
contactReference
是ABRecordRef!
当地址簿联系人提供firstName值时,一切正常。但是如果没有firstName,则应用程序会被.takeRetainedValue()
函数崩溃。似乎if语句没有帮助,因为ABRecordCopyValue()
函数的非托管返回值不是nil,尽管没有firstName。
我希望我能够清楚地解决问题。如果有人能帮我解决一些脑波,那将是很棒的。
答案 0 :(得分:32)
如果我想要与各种属性关联的值,我使用以下语法:
let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String
let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String
或者您可以使用可选绑定:
if let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String {
// use `first` here
}
if let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String {
// use `last` here
}
如果你真的想要返回一个非可选的,其中缺失的值是零长度字符串,你可以使用??
运算符:
let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String ?? ""
let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String ?? ""
答案 1 :(得分:5)
我在这里通过这个功能得到了它:
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
}
您可以在您的财产中使用它,如下所示:
let contactFirstName: String = {
if let firstName: String = rawValueFromABRecordRef(recordRef, forProperty: kABPersonFirstNameProperty) {
return firstName
}
else {
return ""
}
}()
答案 2 :(得分:1)
也许这不只是回答你的问题,但这就是我处理地址簿的方式。
我已定义了自定义运算符:
infix operator >>> { associativity left }
func >>> <T, V> (lhs: T, rhs: T -> V) -> V {
return rhs(lhs)
}
允许以更易读的方式对函数进行多次调用,例如:
funcA(funcB(param))
变为
param >>> funcB >>> funcA
然后我使用此函数将Unmanaged<T>
转换为swift类型:
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
}
和使用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
}
这是打开地址簿,检索所有联系人的代码,每个人都读取了第一个名字和组织(在模拟器中,firstName总是有一个值,而部门没有,所以它&#39;有利于测试):
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)")
}
}
请注意,println
语句会打印可选项,因此您将在控制台Optional("David")
中看到而不只是David
。当然这仅供演示。
回答你的问题的函数是extractUnmanaged
,它接受一个可选的非托管,解包它,检索保留的值为可选,解包它,最后尝试转换为目标类型,这是String
表示名字属性。类型推断负责计算T和V是什么:T是包含在Unmanaged
中的类型,V是返回类型,这是已知的,因为在声明目标变量let firstName: String? = ...
时指定。
我认为您已经负责检查并要求用户获得访问该地址簿的许可。