I have an array of strings within a struct. This populates a list, and I use a .searchable to filter elements there. I can filter them by text, date, or tags within each item. All done without regard for the case.
Now, for the tags, I’m struggling to find the right way to filter them:
let dateFormatter = DateFormatter()
struct LibItem: Codable, Hashable, Identifiable {
let id: UUID
var text: String
var date = Date()
var dateText: String {
dateFormatter.dateFormat = "EEEE, MMM d yyyy, h:mm a"
return dateFormatter.string(from: date)
}
var tags: [String] = []
}
final class DataModel: ObservableObject {
@AppStorage("myapp") public var collectables: [LibItem] = []
init() {
self.collectables = self.collectables.sorted(by: {
$0.date.compare($1.date) == .orderedDescending
})
}
func sortList() {
self.collectables = self.collectables.sorted(by: {
$0.date.compare($1.date) == .orderedDescending
})
}
}
struct ContentView: View {
@EnvironmentObject private var data: DataModel
@State var searchText: String = ""
var body: some View {
NavigationView {
List(filteredItems) { collectable in
VStack(alignment: .leading) {
Spacer()
Text(collectable.text).font(.body).padding(.leading).padding(.bottom, 1)
Spacer()
}
}
.listStyle(.plain)
.searchable(
text: $searchText,
placement: .navigationBarDrawer(displayMode: .always),
prompt: "Search..."
)
}
}
var filteredItems: [LibItem] {
switch selectedItem {
case 1: // date
return data.collectables.filter {
searchText.isEmpty ? true : $0.dateText.localizedCaseInsensitiveContains(searchText)
}
case 2: //tags <--- here how do I search and filter by, case insensitive?
return data.collectables.filter {
searchText.isEmpty ? true : $0.tags.contains(searchText)
}
default:
return data.collectables.filter {
searchText.isEmpty ? true : $0.text.localizedCaseInsensitiveContains(searchText)
}
}
}
}
2
Answers
Compare two lowercased strings, by momentarily turning both sides of the comparison lowercased.
An example you can use in your code:
If you need to check whether each single item of
tags
contains part of the string, you need to iterate:For strict equality, case insensitive:
for substrings, you can use the
range(of:)
method:or, use
localizedCaseInsensitiveContains
which you have already used before: