问题
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
来源:https://stackoverflow.com/questions/25715780/swift-filter-array-using-nspredicate