包含可选的筛选器数组-SearchBar

时间:2018-08-13 11:31:35

标签: ios arrays swift core-data

让您事后了解我的问题。我目前正在为iOS应用编写代码,以处理事件,其中我的GuestList CoreData保存在设备上。

在viewDidLoad上,它将获取coredata对象并将其放置在[GuestDetails]数组中

现在,Guestdetail对象的结构如下:

private(set) public var guestFirstName: String
private(set) public var guestLastName: String?
private(set) public var guestEmail: String?
private(set) public var guestPhone: String?
private(set) public var guestUUID: UUID
private(set) public var guestBarcode: String?
private(set) public var guestCheckedIn: Bool

只有名字,UUID和checkinStatus是强制性的。我已经设置了通过JSON进行添加,但是现在我的问题在我的GuestListViewController上,我有一个搜索栏

Guest List Page

我正在使用以下代码和数组来确保可以过滤。 我有另一个名为

的数组
searchResultArray = [GuestDetails]()

所以从本质上讲,我会将所有来宾详细信息复制到searchResultArray,这就是tableView从中获取其来源的信息。

现在作为搜索的一部分,我使用了在appcoda上找到的这段代码

searchResultArray = guestData.filter({guestData -> Bool in
   (guestData.guestFirstName.lowercased().contains(searchText.lowercased())) || 
   (guestData.guestLastName?.lowercased().contains(searchText.lowercased()))! ||
   (guestData.guestBarcode?.contains(searchText))!
})

问题是我的应用程序崩溃了,如果我仅按名字搜索,它不会崩溃,因为它们被很好地强制展开了,但是如果我添加代码来搜索lastName或Barcode,它将崩溃。我知道这可能是由于显式展开,但是xcode不允许我不展开它。

  • 我尝试使用地图(除非我不太熟悉它,否则无济于事),
  • 我已经尝试过.compact(但由于无法确定它如何访问GuestDetail对象的内部以删除nil,所以无法使它起作用)

  • 问题是[GuestDetails]本身的数组将不包含null,GuestDetails对象中的某些细节可能会因此而崩溃。

我的问题是,如何通过名字(已经可以),姓氏和条形码进行搜索?

谢谢,我希望这个问题足够详尽。

2 个答案:

答案 0 :(得分:2)

我会避免像这样使用强制展开:

searchResultArray = guestData.filter({guestData -> Bool in
    let searchLowercased = searchText.lowercased()
    if guestData.guestFirstName.lowercased().contains(searchLowercased) {
        return true
    }

    if let guestLastName = guestData.guestLastName, guestLastName.lowercased().contains(searchLowercased) {
        return true
    }

    if let guestBarcode = guestData.guestBarcode, guestBarcode.lowercased().contains(searchLowercased) {
        return true
    }

    return false
})

通过注释回答您的问题:您不必在可选对象上使用?运算符,因为我们使用了可选绑定if let语法。例如:

if let guestLastName = guestData.guestLastName,如果guestData.guestLastNamenil,那么我们将跳出这个if statement。那么您会在,中看到if statement,只有在guestData.guestLastName不是nil的情况下,我们才会传递此逗号,这就是为什么我们可以使用guestLastName变量的原因已解包的String并且不再是可选的String?,我们将继续检查搜索词是否与guestLastNamereturn true匹配。

请阅读:if let , if var, guard let,guard var and defer statements in swift

如果您碰巧在数据中添加了另一个属性,并且避免执行所有这些操作,if else可能会更好:

searchResultArray = guestData.filter({guestData -> Bool in
    let searchLowercased = searchText.lowercased()
    let matches:[String?] = [guestData.guestFirstName, guestData.guestLastName, guestData.guestBarcode]
    let nonNilElements = matches.compactMap { $0 }

    for element in nonNilElements {
        if element.lowercased().contains(searchLowercased) {
            return true
        }
    }
    return false
})

答案 1 :(得分:2)

这是一个有趣的小问题,让我们对其进行概括。这是我们的测试数据,可与您的GuestDetails数组进行比较:

struct S {
    var s1 : String
    var s2 : String?
    var s3 : String?
}

var array = [S]()
array.append(S(s1: "test", s2: "yo", s3: "ha"))
array.append(S(s1: "test", s2: nil, s3: nil))
array.append(S(s1: "Howdy", s2: "Bonjour", s3: "Hello"))

let target = "hello"

某些S属性是可选的,而其他则不是。

所以问题是:使用不区分大小写的比较,将array过滤到仅 any S属性包含我们的target字符串的那些元素。

我们可以在一项声明中做到这一点:

let filteredArray = array.filter {
    [$0.s1,$0.s2,$0.s3].compactMap {$0}
        .map {$0.localizedCaseInsensitiveContains(target)}
        .contains(true)
}

效率不如@Ladislav所写,因为即使在找到字符串之后,我们仍在map内循环。但是效率低下可能并不重要。