我正在制作一个使用firebase的实时聊天应用。
在您进行身份验证的应用程序中,当您单击要在所需聊天窗口中的频道时,您将进入视频控制器,即频道列表。我的代码如下所示:
对于频道视图控制器:
import UIKit
import FirebaseAuth
import FirebaseDatabase
enum Section:Int {
case createNewChannelSection = 0
case currentChannelSection
}
class channelsTableViewController: UITableViewController {
// MARK: - Properties
var senderDisplayName: String? // 1
var newChannelTextField: UITextField? // 2
private var channels: [Channel] = []
// MARK: - UITableViewDataSource
// 1
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
// 2
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let currentSection: Section = Section(rawValue: section) {
switch currentSection {
case .createNewChannelSection:
return 1
case .currentChannelSection:
return channels.count
}
} else {
return 0
}
}
// 3
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.currentChannelSection.rawValue {
cell.textLabel?.text = channels[(indexPath as NSIndexPath).row].name
}
return cell
}
// MARK: - UITableViewDelegate
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == Section.currentChannelSection.rawValue {
let channel = channels[(indexPath as NSIndexPath).row]
print("perform segue")
self.performSegue(withIdentifier: "ShowChannel", sender: channel)
}
}
// MARK: - Firebase related methods
private lazy var channelRef: DatabaseReference = Database.database().reference().child("channels")
private var channelRefHandle: DatabaseHandle?
func observeChannels() {
channelRef.observe(.childAdded, with: { (snapshot) in // 1
let channelData = snapshot.value as? [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")
}
})
}
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
title = "Channels"
observeChannels()
}
// MARK: - Actions
@IBAction func createChannel(_ sender: AnyObject) {
if let name = newChannelTextField?.text {
let newChannelRef = channelRef.childByAutoId()
let channelItem = [
"name" : name
]
newChannelRef.setValue(channelItem)
}
}
// MARK: - Navigation
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! ChatViewController
chatVC.channel = channel
print("\(channel)")
chatVC.channelRef = channelRef.child(channel.id)
print("id: \(channel.id)")
print("\(chatVC.channelRef)")
}
}
}
对于我的聊天视图控制器:
import UIKit
import FirebaseDatabase
class ChatViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {
// MARK: - Properties
var channelRef: DatabaseReference?
var channel: Channel? {
didSet {
title = channel?.name
}
}
var messages = [Message]()
@IBOutlet var TableView: UITableView!
@IBOutlet var messageBox: UITextField!
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
TableView.delegate = self
TableView.dataSource = self
self.messageBox.delegate = self
print("chat key: \(String(describing: channelRef?.key))")
observeMessages()
}
// MARK: - Hide text field
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
// MARK: - Source Data
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
if messages.count > 0 {
let message = messages[indexPath.row]
cell.textLabel?.text = message.message
}
return cell
}
// MARK: - Firebase related methods
private lazy var messageRef: DatabaseReference = self.channelRef!.child("messages")
private var newMessageHandle: DatabaseHandle?
func observeMessages() {
print("observe called")
messageRef = channelRef!.child("messages")// Error: force unwrapping nil value
let messageQuery = messageRef.queryLimited(toLast:25)
newMessageHandle = messageQuery.observe(.childAdded, with: { (snapshot) -> Void in
// 3
let messageData = snapshot.value as? [String:AnyObject]
let text = Message()
text.setValuesForKeys(messageData!)
self.messages.insert(text, at: 0)
DispatchQueue.main.async {
self.TableView.reloadData()
}
})
}
// MARK: - Actions
@IBAction func Post(_ sender: AnyObject) {
let msg: [String: AnyObject] = ["message": messageBox.text as AnyObject]
let dbRef = messageRef.childByAutoId()
dbRef.setValue(msg)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
这是我的控制台输出:
perform segue
LearnFirebase.Channel // print("\(channel)")
id: -KvnLy92pj5czfGeA44p // print("id: \(channel.id)")
Optional(https://learnfirebase-2a4a6.firebaseio.com/channels/-KvnLy92pj5czfGeA44p) // print("\(chatVC.channelRef)")
chat key: nil // print("chat key: \(String(describing: channelRef?.key))") on the ChatViewController
observe called
fatal error: unexpectedly found nil while unwrapping an Optional value
2017-10-10 10:18:09.146968+0300 fatal error: unexpectedly found nil while unwrapping an Optional value
当然,会有一次崩溃,因为我强行打开一个零物体,但为什么它没有?我该如何解决这个问题?
感谢您的回答。