Я использую этот код для успешного анализа файла JSON
в tableView
:
struct DetailSections: Decodable {
var detailSections: [DetailSection]
}
struct DetailSection: Decodable {
let title, translation, transcription : String
}
Далее я пытаюсь создать searchBar
для поиска по title
и translation
:
var detailSection = [DetailSection]()
var filteredData = [String]()
var isSearching = false
class SearchViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
search.searchBar.delegate = self
table.dataSource = self
table.delegate = self
view.addSubview(table)
navigationItem.searchController = search
}
func decoder() -> Int {
let url = Bundle.main.url(forResource: "detailSections", withExtension: "json")!
let data = try! Data(contentsOf: url)
let result = try! JSONDecoder().decode(DetailSections.self, from: data)
self.detailSection = result.detailSections
return detailSection.count
}
}
Но я не знаю, что мне делать в этой строке: "???"
extension SearchViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
self.filteredData.removeAll()
guard searchText != "" || searchText != " " else {
print("empty search")
return
}
for item in "???" {
let text = searchText.lowercased()
let isArrayContain = item.lowercased().range(of: text)
if isArrayContain != nil {
print("Search complete")
filteredData.append(item)
}
}
print(filteredData)
if searchBar.text == "" {
isSearching = false
table.reloadData()
} else {
isSearching = true
filteredData = data.filter({$0.contains(searchBar.text ?? "")})
table.reloadData()
}
}
}
Моя таблица:
extension SearchViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching {
return filteredData.count
} else {
return decoder()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailCell", for: indexPath) as! DetailCell
cell.title.text = detailSection[indexPath.row].title
cell.translation.text = detailSection[indexPath.row].translation
cell.transcription.text = detailSection[indexPath.row].transcription
cell.selectionStyle = .none
return cell
}
}
@Sweeper только название, перевод
Это зависит от того, чего вы хотите, но обычно filteredData
должно быть [DetailSection]
.
Без проверки случая для упрощения логики:
for item in detailsSection {
if item.title.contains(searchText) {
filteredData.append(item)
} else if item.translation.contains(searchText) {
filteredData.append(item)
} else {
print("\(searchText) not found title \(item.title) nor in translation \(item.translation))
}
}
Конечно, это можно упростить, но явный код должен объяснять логику.
Боковое примечание:
У вас есть print("empty search")
с возвратом, если поиск пуст, но если вы искали раньше, а затем удалили текст поиска, в вашем случае вы не перезагрузите данные.
Поэтому я бы сделал это вот так в псевдокоде::
Всегда используйте filterData
(в методах DataSource), а detailSection
— это полные данные.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if search.empty() {
filteredData = detailSection //Full data
} else {
filteredData = filterAccordingToSearchText()
}
tableView.reloadData()
}
Теперь пойдем немного дальше:
Вам следует использовать value.range(of: searchText, options: .caseInsensitive) != nil
вместо lowerCase()
для каждого значения.
Так что item.title.contains(searchText)
может быть item.title.range(of: searchText, options: .caseInsensitive) != nil
.
С помощью более высокого метода filter
(но нет ничего плохого в том, чтобы выполнить руководство по циклу, это базовый навык, который вам все равно нужно освоить):
filteredData = detailsSection.filter { item in
if item.title.range(of: searchText, options: .caseInsensitive) != nil {
return true
} else if item.translation.range(of: searchText, options: .caseInsensitive) != nil {
return true
}
return false
}
Полный код должен быть: var DetailSection = DetailSection var filteredData = DetailSection
//Here don't decode EACH time to know the count
func decodeSection() {
let url = Bundle.main.url(forResource: "detailSections", withExtension: "json")!
let data = try! Data(contentsOf: url)
let result = try! JSONDecoder().decode(DetailSections.self, from: data)
self.detailSection = result.detailSections
}
override func viewDidLoad() {
...
decodeSection()
table.reloadData()
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
guard !searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
filteredData = detailSection //search is empty, the "filtered" is equal to put everything
table.reloadData()
return
}
filteredData.removeAll()
//Search Text is NOT empty, we filter
for item in detailSection {
if item.title.contains(searchText) {
filteredData.append(item)
} else if item.translation.contains(searchText) {
filteredData.append(item)
} else {
print("\(searchText) not found title \(item.title) nor in translation \(item.translation) -> Ignored")
}
}
table.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailCell", for: indexPath) as! DetailCell
let item = filteredData[indexPath.row]
cell.title.text = item.title
cell.translation.text = item.translation
cell.transcription.text = item.transcription
cell.selectionStyle = .none
return cell
}
Я хочу искать только title
и translation
. В этой строке filteredData.append(item)
я получаю следующую ошибку: Cannot convert value of type 'DetailSection' to expected argument type 'String'
Это первая строка моего ответа. В TableView вы хотите, чтобы заголовок и перевод отображались только после фильтрации, или вы хотите показывать DetailSection
(с названием и переводом), соответствующие запросу?
Я добавил новый код из tableVIew в вопрос. В моем tableView
есть DetailCell
это вид с title
, translation
, transcription
и несколькими кнопками. Я хочу показать результат поиска, как мое представление, в ячейке с полными элементами (заголовок, перевод, транскрипция и некоторые кнопки). Но я хочу искать в этих ячейках только по названию и переводу.
В вашем ответе filteredData
это массив detailsSection
, но мне нужен какой-то способ фильтрации только для title
и translation
внутри detailsSection
. И я получаю ошибку Cannot convert value of type 'DetailSection' to expected argument type 'String'
Я обновил ответ
Те же проблемы filteredData = detailSection
— невозможно присвоить значение типа «[DetailSection]» типу «[String]».
«filteredData должен быть [DetailSection]»: var filteredData = [DetailSection]()
, а не var filteredData = [String]()
.
В каких свойствах вы хотите искать текст? Все три
title
,translation
иtranscription
?