searchview возвращает пустое значение, когда я ищу - PullRequest
1 голос
/ 06 апреля 2020

Я новичок в Xcode и Swift, но понимание приходит. Проблема сейчас в том, что у меня есть табличное представление с поиском в нем. Когда я запускаю код, данные поступают из API в таблицу правильно, но когда я пытаюсь выполнить поиск, он возвращает пустой список.

Как я могу исправить свой код?

Мой контроллер:

 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()
    }

Класс клиента:

    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
    }

Ответы [ 2 ]

1 голос
/ 07 апреля 2020

Я хотел воспользоваться возможностью, чтобы рассказать вам, что происходит, чтобы вы могли продолжать учиться и укреплять свои навыки. Итак, проблема в том, что ваш метод 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 возвращает "" или ваш метод всегда возвращает false, потому что первый элемент - "" или нажатие default:, которое возвращает false.

На основании предоставленного вами кода client никогда не упорядочивается. Это означает, что каждый раз, когда срабатывает метод searchBar(_ textDidChange:...), это всегда одно и то же, никогда не меняется внутри вашего замыкания. Итак, чтобы исправить это, давайте разберем решение.

Решение

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        currentClientDetails = clientDetails.filter({ $0.CLNT_FULLNAME.contains(searchText) })
        clientsTableView.reloadData()
    }

Итак, что происходит внутри этого замыкания против того, что у вас есть? Что именно делает .filter(), и как работает это закрытие? Существует две версии .filter(), и в вашем случае вы используете последовательное замыкание. Это означает, что он вернет [object] на основе данного предиката (формула).

Что такое предикат, данный здесь, и что это за фантазия $0 вообще? Предикат, указанный в .filter(), проверяет каждый элемент в [object] и возвращает истину или ложь для каждого элемента. True, если он содержит некоторые или все совпадения, или false, если нет. Как только замыкание завершается или sequence завершается, оно возвращает заданный объект. В вашем случае это выглядит как [client].

Мне нравится рассматривать метод .filter() как разновидность for _ in 0..X l oop, и это важная концепция, которую следует учитывать при использовании вышеупомянутых $0 необычных вещей. По сути, $0 говорит первый элемент в последовательности по сравнению с чем? или client[0] по сравнению с чем. Это будет начальная последовательность, и она будет продолжаться до тех пор, пока последовательность не будет завершена, то есть число for _ in 0...X.count.

Я надеюсь, что это даст вам возможность подумать и позволит продолжить кодирование. Спасибо за размещение вдумчивого вопроса и активное участие в работе над проблемой.

1 голос
/ 06 апреля 2020

Это исправлено. Я изменил код в моей функции searchBar следующим образом:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        currentClientDetails = clientDetails
        if searchText.isEmpty == false {
        currentClientDetails = clientDetails.filter({ $0.CLNT_FULLNAME.contains(searchText) })
        }

        clientsTableView.reloadData()
    }

Теперь он возвращает только искомые. Это чувствительное к регистру, нечувствительное к регистру частичное совпадение, начало совпадения и окончание совпадения. Также, когда поле поиска пусто, отображаются все данные.

...