Swift filter array using NSPredicate

匿名 (未验证) 提交于 2019-12-03 08:48:34

问题:

I have an application written in Swift that is pulling in the users contacts from their address book.

I want to filter out the contact that only contain a company name (so that you get your "assumed" real person contact and not businesses)

Here is how this is being accomplish in the Objective-C version of my app:

NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);  NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id person, NSDictionary *bindings) {     NSString *firstName = CFBridgingRelease(ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonFirstNameProperty));     NSString *lastName  = CFBridgingRelease(ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonLastNameProperty));      return (firstName || lastName); }];  NSArray *peopleNotCompanies = [allContacts filteredArrayUsingPredicate:predicate]; 

This works perfectly, so here is my attempt to do this in Swift:

var contactList: NSArray = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue()  var predicate: NSPredicate = NSPredicate { (AnyObject person, NSDictionary bindings) -> Bool in     var firstName: String = ABRecordCopyValue(person as ABRecordRef, kABPersonFirstNameProperty).takeRetainedValue() as String     var lastName: String = ABRecordCopyValue(person as ABRecordRef, kABPersonLastNameProperty).takeRetainedValue() as String      return firstName || lastName }) 

Now this has a couple problems. I am getting these errors on the return statement and the end of the predicate call:

How can I provide similar functionality found in my ObjC code in Swift? Or is there a better way in swift to check if a contact has ONLY a company name and then omit it from the final array?

Thanks!

回答1:

If you have firstName and lastName be optional strings, you can compare them against nil and use them in a boolean expression.

Your second error is due to the extra paren after your closure. This code should work.

var predicate: NSPredicate = NSPredicate { (AnyObject person, NSDictionary bindings) -> Bool in     var firstName: String? = ABRecordCopyValue(person as ABRecordRef, kABPersonFirstNameProperty).takeRetainedValue() as? String     var lastName: String? = ABRecordCopyValue(person as ABRecordRef, kABPersonLastNameProperty).takeRetainedValue() as? String      return firstName != nil || lastName != nil } 


回答2:

If you convert the NSArray into a Swift Array, you can use Swift's Array.filter method. Here's an example with simpler objects for clarity:

let arrObjc: NSArray = ["aaa", "bab", "bbb", "baa", "cbc"] let arr: [AnyObject] = arrObjc //create a swift array with same data  // filter takes a block that returns a boolean. True: keep the item, False: drop it. arr.filter{   if let s = $0 as? String {  // first try to cast AnyObject to our expected type.     return contains(s, "a")   // return true if we want this item, false otherwise.   } else {     return false              // this object is of the wrong type, return false.   } }  // returns: ["aaa", "bab", "baa"] 


回答3:

Your test at the last line in Objective-C will return if firstName is nil or if lastName is nil. In your swift code, you are just trying to compare two strings as if they were Bools. Instead, you want to return if firstName exists, so you should instead do this in both your objective-c and Swift code:

return firstName != nil 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!