searchview returns 搜索时空白
searchview returns blank when I search
我是 Xcode 和 Swift 的新手,但理解即将到来。现在的问题是我有一个 table 视图,里面有一个搜索视图。当我 运行 代码时,数据从 api 正确接收到 table 视图,但是当我尝试进行搜索时,它的 returns 是一个空列表。
如何更正我的代码?
我的控制器:
var clientDetails = [Client]()
var currentClientDetails = [Client]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentClientDetails.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "clients_list") as? ClientCellTableViewCell else { return UITableViewCell() }
cell.nameLb.text = "Name: " + currentClientDetails[indexPath.row].CLNT_FULLNAME
cell.emailLb.text = "Email: " + currentClientDetails[indexPath.row].CLNT_EMAIL
cell.phonenumberLb.text = "Phone Number: " + currentClientDetails[indexPath.row].CLNT_PHONE
cell.clientidLb.text = "ID: " + currentClientDetails[indexPath.row].CLNT_CODE
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.clientsTableView.delegate = self
self.clientsTableView.dataSource = self
fetchData()
setUpSearchBar()
alterLayout()
}
func alterLayout() {
clientsTableView.tableHeaderView = UIView()
// search bar in section header
clientsTableView.estimatedSectionHeaderHeight = 50
// search bar in navigation bar
//navigationItem.leftBarButtonItem = UIBarButtonItem(customView: searchBar)
navigationItem.titleView = searchBar
searchBar.showsScopeBar = false // you can show/hide this dependant on your layout
searchBar.placeholder = "Search Client by Name"
}
private func setUpSearchBar() {
searchBar.delegate = self
}
func fetchData(){
let myapiurl = URL(string: "https://fpay.com/api")
guard let downloadURL = myapiurl else { return }
URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
DispatchQueue.main.async {
let alert = UIAlertController(title: "Fofoofo Pay", message: "Please try again or check your internet connection", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
return
}
print("JSON downloaded")
do
{
let decoder = JSONDecoder()
let downloadedJson = try decoder.decode(Client_details.self, from: data)
self.clientDetails = downloadedJson.client_details
self.currentClientDetails = self.clientDetails
DispatchQueue.main.async {
self.clientsTableView.reloadData()
}
} catch {
print(error)
}
}.resume()
}
// Search Bar
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentClientDetails = clientDetails.filter({ client -> Bool in
switch searchBar.selectedScopeButtonIndex {
case 0:
if searchText.isEmpty { return true }
return client.CLNT_FULLNAME.lowercased().contains(searchText.lowercased())
default:
return false
}
})
clientsTableView.reloadData()
}
客户class:
Client_details: Codable {
let client_details: [Client]
init(client_details: [Client]) {
self.client_details = client_details
}
}
class Client:Codable {
let CLNT_CODE:String
let CLNT_FULLNAME:String
let CLNT_PHONE:String
let CLNT_EMAIL:String
init(CLNT_CODE:String, CLNT_FULLNAME:String, CLNT_PHONE:String, CLNT_EMAIL:String) {
self.CLNT_CODE = CLNT_CODE
self.CLNT_FULLNAME = CLNT_FULLNAME
self.CLNT_PHONE = CLNT_PHONE
self.CLNT_EMAIL = CLNT_EMAIL
}
这是固定的。我将 searchBar 函数中的代码更改为:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentClientDetails = clientDetails
if searchText.isEmpty == false {
currentClientDetails = clientDetails.filter({ [=10=].CLNT_FULLNAME.contains(searchText) })
}
clientsTableView.reloadData()
}
现在returns只有搜索到的-区分大小写,不区分大小写,部分匹配,匹配开始,匹配结束。此外,当搜索字段为空时,它会显示所有数据。
我想借此机会向您详细介绍正在发生的事情,以便您可以继续学习并提高您的技能。所以你遇到的问题是你的 searchBar(_ textDidChange:...)
方法没有按照你期望的方式进行过滤。特别是这段代码。
currentClientDetails = clientDetails.filter({ client -> Bool in
switch searchBar.selectedScopeButtonIndex {
case 0:
if searchText.isEmpty { return true }
return client.CLNT_FULLNAME.lowercased().contains(searchText.lowercased())
default:
return false
}
})
没有产生任何结果的可能原因有两个。原因 #1,您的 client.CLNT_FULLNAME
是 returning ""
或者您的方法总是 returning false 因为第一个元素是 ""
或命中 default:
其中 return 是错误的。
根据您提供的代码,client
永远不会被排序。这意味着每次 searchBar(_ textDidChange:...)
方法被命中时它总是一样的,永远不会在你的闭包内部改变。因此,为了解决这个问题,让我们分解解决方案。
解决方案
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentClientDetails = clientDetails.filter({ [=11=].CLNT_FULLNAME.contains(searchText) })
clientsTableView.reloadData()
}
那么,这个闭包内部发生了什么与您拥有的是什么? .filter()
到底做了什么,闭包是如何工作的? .filter()
有两个版本,在您的情况下,您使用的是顺序闭包。这意味着它将 return 基于给定谓词(公式)的 [object]
。
这里给出的谓词是什么,它有什么特别之处[=22=]
? .filter()
中给出的谓词正在检查 [object]
中的每个元素,并且 return 为每个元素判断真假。如果它包含部分或全部匹配项,则为真,否则为假。一旦闭包完成,或者 序列 完成,它 return 就是一个给定的对象。在您的情况下,它似乎是 [client]
.
我喜欢将 .filter()
方法视为一种 for _ in 0..X
循环,当您使用上述那些 [=22=]
看起来很花哨的东西时,这是一个需要考虑的重要概念。本质上 [=22=]
是说序列中的第一个元素与什么相比?或 client[0]
与什么相比。这将是初始序列,它将一直持续到序列完成,也就是 for _ in 0...X.count
.
的计数
我希望这能给您一些考虑并让您继续编码。感谢您提出深思熟虑的问题并积极参与解决问题。
我是 Xcode 和 Swift 的新手,但理解即将到来。现在的问题是我有一个 table 视图,里面有一个搜索视图。当我 运行 代码时,数据从 api 正确接收到 table 视图,但是当我尝试进行搜索时,它的 returns 是一个空列表。
如何更正我的代码?
我的控制器:
var clientDetails = [Client]()
var currentClientDetails = [Client]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentClientDetails.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "clients_list") as? ClientCellTableViewCell else { return UITableViewCell() }
cell.nameLb.text = "Name: " + currentClientDetails[indexPath.row].CLNT_FULLNAME
cell.emailLb.text = "Email: " + currentClientDetails[indexPath.row].CLNT_EMAIL
cell.phonenumberLb.text = "Phone Number: " + currentClientDetails[indexPath.row].CLNT_PHONE
cell.clientidLb.text = "ID: " + currentClientDetails[indexPath.row].CLNT_CODE
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.clientsTableView.delegate = self
self.clientsTableView.dataSource = self
fetchData()
setUpSearchBar()
alterLayout()
}
func alterLayout() {
clientsTableView.tableHeaderView = UIView()
// search bar in section header
clientsTableView.estimatedSectionHeaderHeight = 50
// search bar in navigation bar
//navigationItem.leftBarButtonItem = UIBarButtonItem(customView: searchBar)
navigationItem.titleView = searchBar
searchBar.showsScopeBar = false // you can show/hide this dependant on your layout
searchBar.placeholder = "Search Client by Name"
}
private func setUpSearchBar() {
searchBar.delegate = self
}
func fetchData(){
let myapiurl = URL(string: "https://fpay.com/api")
guard let downloadURL = myapiurl else { return }
URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
DispatchQueue.main.async {
let alert = UIAlertController(title: "Fofoofo Pay", message: "Please try again or check your internet connection", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
return
}
print("JSON downloaded")
do
{
let decoder = JSONDecoder()
let downloadedJson = try decoder.decode(Client_details.self, from: data)
self.clientDetails = downloadedJson.client_details
self.currentClientDetails = self.clientDetails
DispatchQueue.main.async {
self.clientsTableView.reloadData()
}
} catch {
print(error)
}
}.resume()
}
// Search Bar
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentClientDetails = clientDetails.filter({ client -> Bool in
switch searchBar.selectedScopeButtonIndex {
case 0:
if searchText.isEmpty { return true }
return client.CLNT_FULLNAME.lowercased().contains(searchText.lowercased())
default:
return false
}
})
clientsTableView.reloadData()
}
客户class:
Client_details: Codable {
let client_details: [Client]
init(client_details: [Client]) {
self.client_details = client_details
}
}
class Client:Codable {
let CLNT_CODE:String
let CLNT_FULLNAME:String
let CLNT_PHONE:String
let CLNT_EMAIL:String
init(CLNT_CODE:String, CLNT_FULLNAME:String, CLNT_PHONE:String, CLNT_EMAIL:String) {
self.CLNT_CODE = CLNT_CODE
self.CLNT_FULLNAME = CLNT_FULLNAME
self.CLNT_PHONE = CLNT_PHONE
self.CLNT_EMAIL = CLNT_EMAIL
}
这是固定的。我将 searchBar 函数中的代码更改为:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentClientDetails = clientDetails
if searchText.isEmpty == false {
currentClientDetails = clientDetails.filter({ [=10=].CLNT_FULLNAME.contains(searchText) })
}
clientsTableView.reloadData()
}
现在returns只有搜索到的-区分大小写,不区分大小写,部分匹配,匹配开始,匹配结束。此外,当搜索字段为空时,它会显示所有数据。
我想借此机会向您详细介绍正在发生的事情,以便您可以继续学习并提高您的技能。所以你遇到的问题是你的 searchBar(_ textDidChange:...)
方法没有按照你期望的方式进行过滤。特别是这段代码。
currentClientDetails = clientDetails.filter({ client -> Bool in
switch searchBar.selectedScopeButtonIndex {
case 0:
if searchText.isEmpty { return true }
return client.CLNT_FULLNAME.lowercased().contains(searchText.lowercased())
default:
return false
}
})
没有产生任何结果的可能原因有两个。原因 #1,您的 client.CLNT_FULLNAME
是 returning ""
或者您的方法总是 returning false 因为第一个元素是 ""
或命中 default:
其中 return 是错误的。
根据您提供的代码,client
永远不会被排序。这意味着每次 searchBar(_ textDidChange:...)
方法被命中时它总是一样的,永远不会在你的闭包内部改变。因此,为了解决这个问题,让我们分解解决方案。
解决方案
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentClientDetails = clientDetails.filter({ [=11=].CLNT_FULLNAME.contains(searchText) })
clientsTableView.reloadData()
}
那么,这个闭包内部发生了什么与您拥有的是什么? .filter()
到底做了什么,闭包是如何工作的? .filter()
有两个版本,在您的情况下,您使用的是顺序闭包。这意味着它将 return 基于给定谓词(公式)的 [object]
。
这里给出的谓词是什么,它有什么特别之处[=22=]
? .filter()
中给出的谓词正在检查 [object]
中的每个元素,并且 return 为每个元素判断真假。如果它包含部分或全部匹配项,则为真,否则为假。一旦闭包完成,或者 序列 完成,它 return 就是一个给定的对象。在您的情况下,它似乎是 [client]
.
我喜欢将 .filter()
方法视为一种 for _ in 0..X
循环,当您使用上述那些 [=22=]
看起来很花哨的东西时,这是一个需要考虑的重要概念。本质上 [=22=]
是说序列中的第一个元素与什么相比?或 client[0]
与什么相比。这将是初始序列,它将一直持续到序列完成,也就是 for _ in 0...X.count
.
我希望这能给您一些考虑并让您继续编码。感谢您提出深思熟虑的问题并积极参与解决问题。