2017-02-17 86 views
0

我有和這裏幾乎相同的問題:Firebase get child ID swift ios,並且與此問題Retrieve randomly generated child ID from Firebase略有不同。使用UITableViewController從Firebase獲取當前子ID從

我有一個UITableViewController用戶可以創建自己的渠道。每個人都可以看到這些頻道,每個人都可以點擊其中一個頻道,並進入新視角。現在,當用戶點擊任何這些單元格時,我想獲取當前的頻道ID,用戶剛剛點擊。

我的數據庫看起來像這樣:channel database

現在我的問題是:我怎樣才能像電流ID(-KdD6 [...] Q0Q)?問題2的答案會爲房間的創建者做訣竅,但由於他們沒有創建密鑰而不能被其他用戶使用。可以使用問題1的答案,但到目前爲止,它只是循環遍歷每個隨機密鑰。但是我需要與用戶當前所在頻道相關的密鑰。下面是一些代碼,用於說明我現在如何製作頻道。提前致謝。編輯:這是我的所有代碼。在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:我讀有關的賽格瑞準備,但是這不過將無法正確執行:

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

爲賽格瑞函數執行的準備,但如果讓信道=發送者作爲?頻道不是,因爲它是零。

+0

顯示您身在何處頻道添加對象的代碼也有設置通道對象的ID屬性,當你設置它的名字,如果你已經設置比你想這個頻道ID傳遞到新的屏幕ShowChannel? –

+0

我增加了更多的代碼,現在你可以看到我正在做什麼。我只想要檢索房間的ID,不僅是爲了創建者,而且也是爲了那些想加入這個房間的人。 – Petravd1994

回答

1

您必須查詢Firebase的密鑰。您當前的設置唯一的問題是您要防止重複的名稱。原因在於,如果您沒有將每個頻道的所有密鑰都存儲在應用程序中並且必須查詢密鑰,那麼查詢確切密鑰的唯一方法是通過單獨節點「名稱」。如果存在重複的名稱,則添加到您選擇的行方法的代碼中的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) 
    } 
} 

我建議你得到的所有數據上來看通道並負載:

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所以任何時候你創建一個新的活動通道這個代碼將被調用並重新載入你的表。

否則,你可以得到他們直接鍵的同時創造出聲道:

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

}

只要注意,如果你走這條路線沒有活動的偵聽器的任何新項目增加,這意味着如果另一個設備正在添加一個頻道,那麼其他設備將無法獲得更新。最好通過查詢從firebase中獲取新創建的數據,並在將數據添加到數組時重新載入表。

下面是一個示例通道類應該針對上述工作:

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編碼風格,你應該檢查一下。它使應用程序更加高效。您可以使用此通道模型並添加數據檢索編碼,以便此類處理控制器的數據。這遠遠超出了你的帖子的範圍。現在這個班應該工作。

編輯從最後評論: 在頻道選擇期間而不是在if後面添加您的prepareforsegue方法,因爲它可能在查詢完成之前執行準備for segue。有一件事要注意,而且在我意識到這一點之前,我曾經和你做過一樣的事情;是因爲它在你的本地數組中,所以你不必運行一個查詢來獲取所選單元格的數據。那麼,目前你只是在聽添加的孩子。您可以監聽已刪除和更改的孩子,以便您的本地數據始終得到更新,然後當您選擇該單元格時,您可以直接訪問filteredChannels/channels陣列,並通過prepareforsegue方法推送該頻道。我開始這樣做,因爲在選擇表格期間查詢總是會導致奇怪的錯誤,我不得不尋找創造性的方法。

childRemoved和childChanged查詢可以像您當前的.childAdded方法一樣實現,因爲您希望讓處理程序讓偵聽器在頁面deinit中將其刪除。但是,如果您不允許刪除頻道或更新,則可以忽略此項。

+0

謝謝您的時間來回答這個問題。當我嘗試將第一個代碼塊添加到我的項目中時,出現錯誤「類型[Channel]的值沒有成員'name'」。你知道如何解決這個錯誤嗎? – Petravd1994

+0

Channel類是否是同一個swift文件的一部分?最好創建一個名爲Channel.swift的新swift文件作爲NSObject的子類。我會用適合你的這個例子更新我的答案。 – matthew

+0

是的,內部課程已經是一個單獨的文件,但是如果我沒有這樣說,很抱歉。我將你的代碼複製到了我的Channel.swift文件中,但我再次得到相同的錯誤... – Petravd1994