gpt4 book ai didi

swift - 使用 UITableViewController 从 Firebase 获取当前子 ID

转载 作者:行者123 更新时间:2023-11-28 15:51:03 25 4
gpt4 key购买 nike

我的问题几乎和这里一样:Firebase get child ID swift ios与这个问题略有不同 Retrieve randomly generated child ID from Firebase .

我有一个 UITableViewController,用户可以在其中创建自己的 channel 。每个人都可以查看这些 channel ,每个人都可以点击其中一个 channel ,然后进入一个新的 View 。现在,当用户点击这些单元格中的任何一个时,我想获取用户刚刚点击的当前 channel ID。

我的数据库看起来像这样:channel database

现在我的问题是:如何获得当前 ID (-KdD6[...]Q0Q)?问题 2 的答案对房间的创建者有用,但不能被其他用户使用,因为他们没有创建 key 。可以使用问题 1 的答案,但截至目前,它只是循环遍历每个随 secret 钥。但我需要与用户当前所在 channel 相关的 key 。下面是一些代码,用于展示我目前如何创建 channel 。提前致谢。编辑:这是我所有的代码。我现在在 didSelectRow 函数中收到错误“[Channel] 类型的值没有成员‘name’”。

import UIKit
import Firebase
import Foundation

enum Section: Int {
case createNewChannelSection = 0
case currentChannelsSection
}

extension multiplayerChannelView: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
}

class multiplayerChannelView: UITableViewController {


// MARK: Properties
var channels: [Channel] = []
let searchController = UISearchController(searchResultsController: nil)
var filteredChannels = [Channel]()
private lazy var channelRef: FIRDatabaseReference = FIRDatabase.database().reference().child("channels")
private var channelRefHandle: FIRDatabaseHandle?
var senderDisplayName: String?
var newChannelTextField: UITextField?


override func viewDidLoad() {
super.viewDidLoad()
title = "Rooms"
observeChannels()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
}
deinit {
if let refHandle = channelRefHandle {
channelRef.removeObserver(withHandle: refHandle)
}
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredChannels = channels.filter { Channel in
return (Channel.name.lowercased().range(of: searchText.lowercased()) != nil)
}

tableView.reloadData()
}
@IBAction func createChannel(_ sender: AnyObject) {
if let name = newChannelTextField?.text {
let newChannelRef = channelRef.childByAutoId()
let channelItem = [ // 3
"name": name
]
newChannelRef.setValue(channelItem)
}
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
private func observeChannels() {
channelRefHandle = channelRef.observe(.childAdded, with: { (snapshot) -> Void in // 1
let channelData = snapshot.value as! Dictionary<String, AnyObject> // 2
let id = snapshot.key
if let name = channelData["name"] as! String!, name.characters.count > 0 { // 3
self.channels.append(Channel(id: id, name: name))
self.tableView.reloadData()
} else {
print("Error! Could not decode channel data")
}
})
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let currentSection: Section = Section(rawValue: section) {
switch currentSection {
case .createNewChannelSection:
return 1

case .currentChannelsSection:
if searchController.isActive && searchController.searchBar.text != "" {
return filteredChannels.count
}
else{
return channels.count
}
}
} else {
return 0
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let reuseIdentifier = (indexPath as NSIndexPath).section == Section.createNewChannelSection.rawValue ? "NewChannel" : "ExistingChannel"
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)

if (indexPath as NSIndexPath).section == Section.createNewChannelSection.rawValue {
if let createNewChannelCell = cell as? CreateChannelCell {
newChannelTextField = createNewChannelCell.newChannelNameField
}
} else if (indexPath as NSIndexPath).section == Section.currentChannelsSection.rawValue {
if searchController.isActive && searchController.searchBar.text != "" {
cell.textLabel?.text = filteredChannels[(indexPath as NSIndexPath).row].name
} else {
cell.textLabel?.text = channels[(indexPath as NSIndexPath).row].name
}
}

return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == Section.currentChannelsSection.rawValue {
var channel = channels
if searchController.isActive && searchController.searchBar.text != "" {
channel = [filteredChannels[(indexPath as NSIndexPath).row]]
channelRef.queryOrdered(byChild: "name").queryEqual(toValue: channel.name).observe(.childAdded, with: {snapshot in
let currentID = snapshot.key
print(currentID)
})
}
else
{
channel = [channels[(indexPath as NSIndexPath).row]]
channelRef.queryOrdered(byChild: "name").queryEqual(toValue: channel.name).observe(.childAdded, with: {snapshot in
let currentID = snapshot.key
print(currentID)
})
}

self.performSegue(withIdentifier: "ShowChannel", sender: channel)
}
}

}

internal class Channel {
internal let id: String
internal let name: String

init(id: String, name: String) {
self.id = id
self.name = name
}
}

编辑 2:我阅读了关于 prepare for segue 的内容,但是这不会正确执行:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let channel = sender as? Channel {
let chatVc = segue.destination as! channelMultiplayerViewController
chatVc.channel = channel
chatVc.channelRef = channelRef.child(channel.id)
}
}

执行 prepare for segue 函数,但是 if let channel = sender as? Channel 不是,因为它是 nil。

最佳答案

您必须向 firebase 查询 key 。当前设置的唯一问题是您希望防止重复名称。这样做的原因是,如果您没有在应用程序中存储每个 channel 的所有 key 并且必须查询 key ,则查询确切 key 的唯一方法是通过单独的节点“名称”。如果存在重复名称,那么我添加到您的 did select row 方法的代码中的 childAdded 将返回两个,并且没有其他数据可以帮助识别它。

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == Section.currentChannelsSection.rawValue {
var channel = channels
if searchController.isActive && searchController.searchBar.text != "" {
channel = [filteredChannels[(indexPath as NSIndexPath).row]]
channelRef.queryOrdered(byChild: "name").queryEqual(toValue: channel.name).observe(.childAdded, with: {snapshot in
let currentID = snapshot.key
})
}
else
{
channel = [channels[(indexPath as NSIndexPath).row]]
channelRef.queryOrdered(byChild: "name").queryEqual(toValue: channel.name).observe(.childAdded, with: {snapshot in
let currentID = snapshot.key
})
}
self.performSegue(withIdentifier: "ShowChannel", sender: channel)
}
}

我建议您获取已加载的所有 channel 的数据:

override func viewDidLoad(){
channelRef.observe(.childAdded, with: {snapshot in
let data = snapshot.value as? [String:Any] ?? [:]
let key = snapshot.key
let name = data["name"]
let chnl = Channel.init(id:key, name:name)
self.channels.append(chnl)
self.tableView.reloadData()
})
}

当您使用 .childAdded 时,此 VC 的监听器将处于事件状态,因此无论您何时创建新 channel ,都会调用此代码并重新加载您的表格。

否则您可以在创建 channel 时直接获取他们的 key :

@IBAction func createChannel(_ sender: AnyObject) {
if let name = newChannelTextField?.text {
let newChannelRef = channelRef.childByAutoId()
let channelItem = [
"name": name
]
newChannelRef.setValue(channelItem)
let channelKey = newChannelRef.key
let newChannel = Channel.init(id:channelKey, name:name)
self.channels.append(newChannel)
self.tableView.reloadData()
}

请注意,如果您走这条路线,则不会有任何新添加的项目的活跃监听器,这意味着如果另一台设备正在添加 channel ,那么其他设备将不会获得更新。最好通过查询从 firebase 中获取新创建的数据,并在将数据添加到数组时重新加载表。

这是一个适用于上述情况的示例 Channel 类:

import Foundation
// import FirebaseDatabase // import this if you would like to use this class to handle data transactions

class Channel: NSObject {
// change either of these to var if they should be mutable
let id:String
let name:String
// initialize
init (_ id:String, name:String){
self.id = id
self.name = name
}
}

这样您就有了一个可以使用的模型对象。如果您不熟悉 MVC 编码风格,您应该检查一下。它使应用程序更加高效。您可以采用此 Channel 模型并添加数据检索编码,以便此类为您的 Controller 处理数据。不过,这远远超出了您帖子的范围。现在这个类应该工作。

根据最后一条评论编辑:在 channel 选择期间在两个查询 block 中添加您的 prepareforsegue 方法,而不是在 if block 之后,因为它可能会在查询完成之前执行 prepare for segue。不过要注意一件事,在我意识到这一点之前,我曾经和你做过同样的事情;是您此时不必运行查询来获取所选单元格的数据,因为它在您的本地数组中。嗯,目前你只听添加的 child 。您还可以监听已删除和更改的子项,以便始终更新您的本地数据,然后当您选择单元格时,您可以直接访问 filteredChannels/channels 数组并通过 prepareforsegue 方法推送 channel 。我开始这样做是因为在表选择期间查询总是会导致奇怪的错误,我必须找到创造性的方法。

childRemoved 和 childChanged 查询可以像您当前的 .childAdded 方法一样实现,因为您希望保留监听器的处理程序以在页面取消时删除它们。但是,如果您不允许删除或更新 channel ,则可以忽略它。

关于swift - 使用 UITableViewController 从 Firebase 获取当前子 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42308435/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com