Swift: Firebase Chat App Part 10 - Fetching Users & Photos (Real-time) - Xcode 11 - 2020
StorageManager.shared.downloadURL(for: path) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let url):
self.downloadImage(imageView: imageView, url: url)
case .failure(let error):
print(error.localizedDescription)
break
}
}
downloadURL
을 호출 func downloadURL(for path: String, completionHandler: @escaping (Result<URL, Error>) -> Void) {
let reference = storage.child(path)
reference.downloadURL { result in
switch result {
case .failure(let error):
completionHandler(.failure(StorageErrors.failedtToGetDownloadUrl))
case .success(let url):
completionHandler(.success(url))
}
}
}
func downloadImage(imageView: UIImageView, url: URL) {
URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
guard let self = self else { return }
guard
let data = data,
error == nil else {
return
}
let image = UIImage(data: data)
DispatchQueue.main.async {
imageView.image = image
}
}
.resume()
}
func insertUser(with user: ChatAppUser, completionHandler: @escaping (Bool) -> Void) {
database.child(user.safeEmail).setValue([
"first_name" : user.firstName,
"last_name" : user.lastName,
"platform" : user.platform.rawValue,
"userIdentifier" : user.userIdentifier ?? ""
]) { error, reference in
guard error == nil else {
print("Failed to write to database")
completionHandler(false)
return
}
/*
users =>
[
[
"name":
"safe_email":
],
[
"name":
"safe_email":
]
]
*/
self.database.child("users").observeSingleEvent(of: .value) { snapshot in
if var usersCollection = snapshot.value as? [[String : String]] {
// append to user dict
let newElement = [
"name" : user.firstName + " " + user.lastName,
"email" : user.safeEmail,
"platform" : user.platform.rawValue
]
usersCollection.append(newElement)
self.database.child("users").setValue(usersCollection) { error, _ in
guard error == nil else {
completionHandler(false)
return
}
completionHandler(true)
}
} else {
// create that dictionary
let newCollection: [[String:String]] = [
[
"name" : user.firstName + " " + user.lastName,
"email" : user.safeEmail,
"platform" : user.platform.rawValue
]
]
self.database.child("users").setValue(newCollection) { error, _ in
guard error == nil else {
completionHandler(false)
return
}
completionHandler(true)
}
}
}
}
}
insertUser
변경users
디렉토리에 추가 func getAllUsers(completionHandler: @escaping (Result<[[String : String]], Error>) -> ()) {
database.child("users").observeSingleEvent(of: .value) { snapshot in
guard let value = snapshot.value as? [[String : String]] else {
completionHandler(.failure(DatabaseErrors.failedToFetch))
return
}
completionHandler(.success(value))
}
}
private var users = [[String : String]]()
// firebase items
private var hasFetched = false
// check whether it has been checked or not
private var results = [[String : String]]()
NewConversationViewController
사용 변수users
및 패치 여부를 판단하는 플래그 비트 hasFetched
, 검색 쿼리문에 따라 필터링된 결과값을 리턴하는 results
extension NewConversationViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard
let text = searchBar.text,
!text.replacingOccurrences(of: " ", with: "").isEmpty else {
return
}
searchBar.resignFirstResponder()
results.removeAll()
spinner.show(in: view)
searchUsers(query: text)
}
private func searchUsers(query: String) {
// check if array has Firebase results
// if it does: filter
if hasFetched {
filterUsers(with: query)
} else {
// if not, fetch them filter
DatabaseManager.shared.getAllUsers { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let users):
self.hasFetched = true
self.users = users
self.filterUsers(with: query)
case .failure(let error):
print(error.localizedDescription)
}
}
}
// update the UI: either show results or show no result
}
private func filterUsers(with term: String) {
guard hasFetched else { return }
spinner.dismiss()
let results: [[String : String]] = users.filter { user in
guard let name = user["name"]?.lowercased() as? String else {
return false
}
if term.count > name.count {
// "Junyeong Park" "Park"
return false
} else {
for offset in 0...(name.count-term.count) {
let currentIndex = name.index(name.startIndex, offsetBy: offset)
let lastIndex = name.index(currentIndex, offsetBy: term.count)
let subtext = name[currentIndex..<lastIndex]
if term.lowercased() == subtext {
return true
}
}
return false
}
}
self.results = results
updateUI()
}
private func updateUI() {
if results.isEmpty {
self.noResultsLabel.isHidden = false
self.tableView.isHidden = true
} else {
self.noResultsLabel.isHidden = true
self.tableView.isHidden = false
self.tableView.reloadData()
}
}
}
users
를 필터링, 검색 결과를 보여줄지 결정하는 함수filterUsers
를 통해 대소문자에 관계없이 검색 쿼리문과 일치하는 모든 유저의 이름을 리턴isHidden
토글링