-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSearchViewController.swift
More file actions
94 lines (75 loc) · 3.29 KB
/
SearchViewController.swift
File metadata and controls
94 lines (75 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//
// SearchViewController.swift
// Example
//
// Created by Josef Dolezal on 09/10/2018.
// Copyright © 2018 Josef Dolezal. All rights reserved.
//
import UIKit
import MapyAPI
final class SearchViewController: UITableViewController, UISearchBarDelegate {
private let mapyService = MapyAPIService()
private var places = [Place]() {
didSet {
tableView.reloadData()
}
}
private var searchRequestWorkItem: DispatchWorkItem?
// MARK: UITableViewDatasource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchResultCell", for: indexPath)
let place = places[indexPath.row]
cell.textLabel?.text = place.shortDescription
cell.detailTextLabel?.text = place.longDescription
return cell
}
// MARK: UISearchBarDelegate
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// If the phrase is empty, remove search results
guard !searchText.isEmpty else {
searchRequestWorkItem?.cancel()
places = []
return
}
// Since this method is called for every key stroke, we want to debounce the requests.
// We schedule API request with small delay, if phrase is not updated during the delay, we run the request.
// If the phrase is updated, the we cancel the request for previous phrase and schedule new one.
debounceSearchRequest(for: searchText)
}
// MARK: Private API
private func debounceSearchRequest(for phrase: String) {
// If we scheduled request for previous item, cancel it before scheduling next one
searchRequestWorkItem?.cancel()
// Create work item which will make search request for given phrase
let item = DispatchWorkItem { [weak self] in
// Check if the screen still exists
guard let self = self else { return }
// Run the request with two callbacks, update places on success, print error on failure
self.mapyService.suggestions(forPhrase: phrase, count: 10,
completion: { result in
switch result {
case let .success(places):
// Deliver the result on main thread
DispatchQueue.main.async { [weak self] in
self?.places = places
}
case let .failure(error):
print(error)
}
})
}
// Schedule the work item and create strong reference
searchRequestWorkItem = item
DispatchQueue.main.asyncAfter(deadline: .now() + 0.8, execute: item)
}
private func showError(_ error: Error) {
let title = "Something went wrong.."
let okAction = UIAlertAction(title: "Ok :-(", style: .default, handler: { _ in })
let controller = UIAlertController(title: title, message: error.localizedDescription, preferredStyle: .alert)
controller.addAction(okAction)
present(controller, animated: true)
}
}