【问题标题】:Swift filter array using NSPredicate使用 NSPredicate 的 Swift 过滤器数组
【发布时间】:2014-09-07 23:42:06
【问题描述】:

我有一个用 Swift 编写的应用程序,它从用户的通讯录中提取联系人。

我想过滤掉仅包含公司名称的联系人(以便您获得“假定的”真实联系人而不是企业)

这是在我的应用程序的 Objective-C 版本中如何实现的:

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];

这很完美,所以这是我在 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
})

现在这有几个问题。我在 return 语句和谓词调用结束时收到这些错误:

如何在我的 Swift 中的 ObjC 代码中提供类似的功能?或者有没有更好的方法来快速检查联系人是否只有公司名称,然后从最终数组中省略它?

谢谢!

【问题讨论】:

    标签: ios swift abaddressbook


    【解决方案1】:

    如果您有 firstName 和 lastName 是可选字符串,您可以将它们与 nil 进行比较并在布尔表达式中使用它们。

    您的第二个错误是由于您关闭后的额外括号。这段代码应该可以工作。

    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
    }
    

    【讨论】:

    • 如果你使用NSArray而不是Array,那么你可以执行这行代码:let filteredContacts: NSArray = contactList.filteredArrayUsingPredicate(predicate)
    • 感谢您的澄清,额外的 ) 真的让我失望了,因为我没有注意到它!
    【解决方案2】:

    如果将 NSArray 转换为 Swift Array,则可以使用 Swift 的 Array.filter 方法。为了清楚起见,下面是一个包含更简单对象的示例:

    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】:

      如果 firstName 为 nil 或 lastName 为 nil,您在 Objective-C 中最后一行的测试将返回。在您的 swift 代码中,您只是想比较两个字符串,就好像它们是布尔值一样。相反,如果 firstName 存在,您希望返回,因此您应该在 Objective-c 和 Swift 代码中都这样做:

      return firstName != nil
      

      【讨论】:

      • 似乎也不起作用,引发另一种类型的错误。不过,我越是研究这个,似乎我在浪费时间,因为 Swift 没有 filterArrayUsingPredicate: 方法。所以我真的需要检查每个 ABRecordRef,看看名字和姓氏是否为零,而公司值不是,然后忽略那个 ABRecordRef
      • @KyleBegeman Swift 可以访问您在 Objective-C 中可以访问的所有相同方法,您只需要查看 NSArray 而不是 Swift 的原生数组类。新的错误是什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多