Swift – 检查非托pipe地址簿单值属性为零

我是相对新的iOS开发和迅速。 但是到目前为止,我总是能够通过一些关于计算器和一些文档和教程的研究来帮助自己。 但是,还有一个问题,我找不到任何解决scheme。

我想从用户地址簿中获取一些数据(例如,单个值属性kABPersonFirstNameProperty )。 由于.takeRetainedValue()函数会引发错误,如果此联系人没有在.takeRetainedValue()的firstName值,我需要确保ABRecordCopyValue()函数确实返回一个值。 我试图在closures中检查这个:

 let contactFirstName: String = { if (ABRecordCopyValue(self.contactReference, kABPersonFirstNameProperty) != nil) { return ABRecordCopyValue(self.contactReference, kABPersonFirstNameProperty).takeRetainedValue() as String } else { return "" } }() 

contactReferenceABRecordRef!types的variablesABRecordRef!

当地址簿联系人提供firstName值时,一切工作正常。 但是,如果没有名字,则应用程序会通过.takeRetainedValue()函数崩溃。 看来,if语句没有帮助,因为ABRecordCopyValue()函数的非托pipe返回值不是nil,尽pipe没有firstName。

我希望我能够清楚地说明我的问题。 如果有人能帮助我解决一些脑波,那将是非常棒的。

如果我想要与各种属性相关的值,我使用以下语法:

 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 } 

如果你真的想返回一个非可选的,那么缺less的值是一个零长度的string,你可以使用?? 运营商:

 let first = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String ?? "" let last = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String ?? "" 

我通过这个函数得到它:

 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 "" } }() 

也许这不仅仅是回答你的问题,而是我处理地址簿的方式。

我定义了一个自定义运算符:

 infix operator >>> { associativity left } func >>> <T, V> (lhs: T, rhs: T -> V) -> V { return rhs(lhs) } 

允许以更可读的方式将多个调用链接到函数,例如:

 funcA(funcB(param)) 

 param >>> funcB >>> funcA 

然后我使用这个函数将一个Unmanaged<T>转换为一个swifttypes:

 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一起工作的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总是有一个值,而部门没有,所以它是好的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)") } } 

请注意, println语句打印可选项,所以您将在控制台中看到Optional("David")而不仅仅是David 。 当然这只是为了演示。

回答你的问题的函数是extractUnmanaged ,它取一个可选的非托pipe的,解开它,检索保留的值作为可选项,解开它,最后试图转换为目标types,这是String的名字属性。 types推理需要弄清楚什么是T和V:T是包装在Unmanaged的types,V是返回types,这是已知的,因为在声明目标variables时指定let firstName: String? = ... let firstName: String? = ...

我认为你已经照顾了检查,并要求用户访问通讯录的权限。