使用 firebase 连接到 Tableview 的搜索栏
Posted
技术标签:
【中文标题】使用 firebase 连接到 Tableview 的搜索栏【英文标题】:Search bar connected to a Tableview with firebase 【发布时间】:2019-05-22 12:00:57 【问题描述】:我有一个连接到 Tableview 的搜索栏,但我不知道如何使它工作! 表格视图是“记忆”的表格视图。记忆有标题、用户 ID、正文,我希望它也能够按标题搜索。 问题是我正在使用 firebase,但我真的不知道如何在特定用户的特定记忆中搜索以及如何从 Firebase 中获取所有内容。
我尝试了这么多代码行,但没有任何效果。我需要帮助!
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
class MemoryViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, UISearchBarDelegate, UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController)
self.memories = Array.filter( (array: String) -> Bool in
if array.contains(searchController.searchBar.text!)
return true
else
return false
)
self.resultController.tableView.reloadData()
var filteredArray = [Memory]()
var searchController = UISearchController()
var resultController = UITableViewController()
@IBOutlet weak var tbl: UITableView!
@IBOutlet weak var searchBar: UISearchBar!
var memories : [Memory] = []
var ref : DatabaseReference!
let sref = Storage.storage().reference()
var lastIndex : Int = 0
var strMode : String = ""
var filteredData = [String]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return memories.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let identifier = "iden"
var cell : UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
if cell == nil
cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: identifier)
let temp = memories[indexPath.row]
cell?.textLabel?.text = temp.title
cell?.imageView?.image = temp.image
return cell!
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
return true
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
if editingStyle == .delete
let temp = self.memories[indexPath.row]
self.memories.remove(at: indexPath.row)
self.ref.child("MEmories/\(temp.key)").removeValue()
tableView.deleteRows(at: [indexPath as IndexPath], with: .fade)
override func viewDidLoad()
super.viewDidLoad()
ref = Database.database().reference()
let rightButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(MemoryViewController.barButtonItemClicked(_:)))
self.navigationItem.setRightBarButton(rightButton, animated: true)
// Do any additional setup after loading the view.
self.loadMemories()
self.searchController = UISearchController(searchResultsController: resultController)
tbl.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
self.resultController.tableView.delegate = self
self.resultController.tableView.dataSource = self
@objc func barButtonItemClicked(_ sender:UIBarButtonItem)
print("+ clicked")
let addMemoryViewController = self.storyboard?.instantiateViewController(withIdentifier: "AddMemoryViewController") as! AddMemoryViewController
self.strMode = "newMemory"
self.navigationController?.pushViewController(addMemoryViewController, animated: true)
func readFromNSUSerDefault()-> Memory
let d : UserDefaults = UserDefaults.standard
let strTitle = d.object(forKey: "title") as? String
let strBody = d.object(forKey: "body") as? String
let strImageRef = d.object(forKey: "imageRef") as? String
let uid = d.object(forKey: "uid") as? String
let imageData = d.object(forKey: "imageData") as? Data
let key = d.object(forKey: "key") as? String
let m = Memory(title: strTitle!, body: strBody!, key: key!, uid: uid!, imageRef: strImageRef!)
m.image = UIImage(data: imageData!)
m.key = key!
return m
override func viewDidAppear(_ animated: Bool)
let d = UserDefaults.standard
let newMemory = readFromNSUSerDefault()
let userAdded = d.bool(forKey: "userAdded") //key new user = true
let userEdited = d.bool(forKey: "userEdited")//key user edited = true
if self.strMode == "newMemory" && userAdded
self.memories.append(newMemory)
self.tbl.reloadData()
else if self.strMode == "edit" && userEdited
memories[lastIndex] = newMemory
self.tbl.reloadData()
d.set(false, forKey: "userAdded")
d.set(false, forKey: "userEdited")
d.synchronize()
self.strMode = " "
func loadMemories()
self.ref.child("MEmories").queryOrderedByKey().observe(.value, with:
snapShot in
if let dict = snapShot.value as? NSDictionary
for d in (dict as? Dictionary<String,AnyObject>)!
let title = d.value["title"] as?String
let body = d.value["body"] as? String
let uid = d.value["uid"] as? String
let imageRef = d.value["imageRef"] as? String
let m = Memory(title: title!, body: body!, uid: uid!,imageRef:imageRef!)
m.key = d.key
let tempImageRef = self.sref.child(m.imageRef)
tempImageRef.getData(maxSize: 1*1024*1024, completion: (data,error) in
if error == nil
if let imageData = data
m.image = UIImage(data: imageData)
self.memories.append(m)
self.tbl.reloadData()
)
//end of if
self.ref.child("MEmories").removeAllObservers()
)
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
if let identifier = segue.identifier
if identifier == "goToEdit"
let indexPath = self.tbl.indexPathForSelectedRow
let addMemoryViewController = segue.destination as! AddMemoryViewController
self.strMode = "edit"
self.lastIndex = (indexPath?.row)!
addMemoryViewController.mode = self.strMode
addMemoryViewController.current = memories[(indexPath?.row)!]
【问题讨论】:
我需要更改这一行:self.memories = Array.filter( (array: String) 所以它会检查内存的 TITLE 而不仅仅是 MEMORY 你有两个问题合二为一;如何查询 Firebase 实时数据库,然后如何过滤该数据。这两个问题都解决了,实在是太宽泛了。但是要开始,我们需要知道您是要在代码中过滤还是在 Firebase 中过滤,以及您想使用什么流程进行过滤?输入一个字符串并根据该字符串进行过滤,或者逐个字符进行过滤。一旦我们知道了这一点并且您有了解决方案,那么在您的 searchBox 和/或 tableView 中使用它就是另一个问题。 【参考方案1】:您应该将过滤后的值存储在过滤数组中,并在表视图数据委托、数据源方法中使用该数组
将memory数组的所有值存储到loadMemories方法中的filteredArray数组中
if let dict = snapShot.value as? NSDictionary
for d in (dict as? Dictionary<String,AnyObject>)!
//append in memories
self.filteredArray = self.memories
self.tbl.reloadData()
//end of if
在表视图委托数据源方法中使用filteredArray数组
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return filteredArray.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let identifier = "iden"
var cell : UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
if cell == nil
cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: identifier)
let temp = filteredArray[indexPath.row]
cell?.textLabel?.text = temp.title
cell?.imageView?.image = temp.image
return cell!
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
if editingStyle == .delete
let temp = self.filteredArray[indexPath.row]
self.filteredArray.remove(at: indexPath.row)
if let index = self.memories.firstIndex(where: $0.title == temp.title )
self.memories.remove(at: index)
self.ref.child("MEmories/\(temp.key)").removeValue()
tableView.deleteRows(at: [indexPath as IndexPath], with: .fade)
在 updateSearchResults 方法中,通过比较 searchBar 文本和内存对象标题来过滤内存数组
func updateSearchResults(for searchController: UISearchController)
if searchController.searchBar.text!.isEmpty
self.filteredArray = self.memories
else
self.filteredArray = self.memories.filter(
$0.title.localizedCaseInsensitiveContains(searchController.searchBar.text!)
)
self.resultController.tableView.reloadData()
【讨论】:
首先,非常感谢您!您的意思是当我在表视图委托数据源方法中使用filteredArray 数组时,它将不是在那里使用内存数组吗?因为我需要那里的记忆来给特定用户他的特定记忆...... 是的。在表视图委托数据源方法中使用过滤数组数组,而不是使用内存数组。而filteredArray 只是内存数组的副本。所以不会有问题。试试看 抱歉,现在 TableView 中根本不显示记忆了。可能是因为我在表视图委托数据源方法中用过滤数组替换了内存数组。有任何想法吗? :) @ABM 你是否像我提到的那样在loadMemories
方法中添加了self.filteredArray = self.memories self.tbl.reloadData()
?
是的...你知道发生了什么吗?【参考方案2】:
根据评论,这个问题与 Firebase 没有直接关系,但原发帖人在问这个
我想通过内存的标题过滤代码,我还在 卡住了...有什么想法吗? – 反导
所以,这里有一个完整的例子,说明如何按内存标题过滤代码。
让我们从一个简单的类开始来保存一段记忆和它的标题
class MemoryClass
var title = ""
init(withTitle: String)
self.title = withTitle
然后我们将构建一个数组,将其用作例如 tableView 数据源
let m0 = MemoryClass(withTitle: "Gone Fishing")
let m1 = MemoryClass(withTitle: "Wedding")
let m2 = MemoryClass(withTitle: "France Vacation")
let m3 = MemoryClass(withTitle: "Italy Vacation")
let memoriesArray = [m0, m1, m2, m3]
然后是按标题查找内存的代码。在这种情况下,我们要找到标题为“婚礼”的内存
let memoryTitleToFind = "Wedding"
let filteredArray = memoriesArray.filter $0.title == memoryTitleToFind
为了验证是否找到了内存,让我们遍历找到的内存。请记住,如果有多个名为“婚礼”的记忆,那么它会将所有记忆过滤到过滤后的数组中
for foundMemory in filteredArray
print(foundMemory.title)
显示过滤结果的输出是
Wedding
我为此答案创建了一个简单的 MemoryClass,在您的问题中您注意到还有其他属性
内存有标题、用户 ID、正文,我希望它也能够搜索 按标题
因此可以将它们添加到类中并以相同的方式过滤。
【讨论】:
非常感谢你,但我坚持的事情是记忆阵列是动态的。用户可以创建新的记忆或删除记忆,因此使用 firebase 就是它的全部意义所在。非常感谢你。 @ABM 这不是您的评论所说的或您的问题所要求的。您问如何在代码中过滤,这就是解决方案。它适用于“动态”数据,因为只要您的 Firebase 数据发生更改,memoryArray 就会更新。如果您要问其他问题,请更新并澄清问题的真正含义。以上是关于使用 firebase 连接到 Tableview 的搜索栏的主要内容,如果未能解决你的问题,请参考以下文章
使用 Laravel 5.2 连接到 Firebase -“创建资源时出错”
无法将 Firebase 连接到 Android 应用 |此应用无权使用 Firebase 身份验证