让您事后了解我的问题。我目前正在为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上,我有一个搜索栏
我正在使用以下代码和数组来确保可以过滤。 我有另一个名为
的数组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对象中的某些细节可能会因此而崩溃。
我的问题是,如何通过名字(已经可以),姓氏和条形码进行搜索?
谢谢,我希望这个问题足够详尽。
答案 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.guestLastName
是nil
,那么我们将跳出这个if statement
。那么您会在,
中看到if statement
,只有在guestData.guestLastName
不是nil
的情况下,我们才会传递此逗号,这就是为什么我们可以使用guestLastName
变量的原因已解包的String
并且不再是可选的String?
,我们将继续检查搜索词是否与guestLastName
和return 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
内循环。但是效率低下可能并不重要。