我有一个使用Firebase在用户之间发送和接收消息的应用。在将我的代码更新到新的Swift 3以便我可以将iOS 10的酷炫新功能添加到我的应用程序的过程中,我遇到了几个错误。我能够在运行时修复其中的大部分:
Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']''
我不知道是什么导致了这一点。用户的userID在登录时会打印到控制台,但是一旦按下登录按钮,我的应用程序就会崩溃。在我更新到Swift 3之前,这个错误是不存在的,实际上只有在我修复了应用程序的另一部分中的错误之后才出现。
无论如何,我的应用程序中只有两个主要类:LoginViewController
和ChatViewController
。
以下是LoginViewController
的代码:
import UIKit
import Firebase
class LoginViewController: UIViewController {
// MARK: Properties
var ref: FIRDatabaseReference! // 1
var userID: String = ""
override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference() // 2
}
@IBAction func loginDidTouch(_ sender: AnyObject) {
FIRAuth.auth()?.signInAnonymously() { (user, error) in
if let user = user {
print("User is signed in with uid: ", user.uid)
self.userID = user.uid
} else {
print("No user is signed in.")
}
self.performSegue(withIdentifier: "LoginToChat", sender: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepare(for: segue, sender: sender)
let navVc = segue.destinationViewController as! UINavigationController // 1
let chatVc = navVc.viewControllers.first as! ChatViewController // 2
chatVc.senderId = userID // 3
chatVc.senderDisplayName = "" // 4
}
}
以下是ChatViewController
的代码:
import UIKit
import Firebase
import JSQMessagesViewController
class ChatViewController: JSQMessagesViewController {
// MARK: Properties
var rootRef = FIRDatabase.database().reference()
var messageRef: FIRDatabaseReference!
var messages = [JSQMessage]()
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
var userIsTypingRef: FIRDatabaseReference! // 1
private var localTyping = false // 2
var isTyping: Bool {
get {
return localTyping
}
set {
// 3
localTyping = newValue
userIsTypingRef.setValue(newValue)
}
}
var usersTypingQuery: FIRDatabaseQuery!
override func viewDidLoad() {
super.viewDidLoad()
title = "ChatChat"
setupBubbles()
// No avatars
collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSize.zero
collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSize.zero
messageRef = rootRef.child("messages")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
observeMessages()
observeTyping()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
}
func collectionView(collectionView: JSQMessagesCollectionView!,
messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
func collectionView(collectionView: JSQMessagesCollectionView!,
messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item] // 1
if message.senderId == senderId { // 2
return outgoingBubbleImageView
} else { // 3
return incomingBubbleImageView
}
}
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return messages.count
}
func collectionView(collectionView: JSQMessagesCollectionView!,
avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
private func setupBubbles() {
let factory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = factory?.outgoingMessagesBubbleImage(
with: UIColor.jsq_messageBubbleBlue())
incomingBubbleImageView = factory?.incomingMessagesBubbleImage(
with: UIColor.jsq_messageBubbleLightGray())
}
func addMessage(id: String, text: String) {
let message = JSQMessage(senderId: id, displayName: "", text: text)
messages.append(message!)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{
let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
let message = messages[indexPath.item]
if message.senderId == senderId {
cell.textView!.textColor = UIColor.white()
} else {
cell.textView!.textColor = UIColor.black()
}
return cell
}
func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!,
senderDisplayName: String!, date: NSDate!) {
let itemRef = messageRef.childByAutoId() // 1
let messageItem = [ // 2
"text": text,
"senderId": senderId
]
itemRef.setValue(messageItem as? AnyObject) // 3
// 4
JSQSystemSoundPlayer.jsq_playMessageSentSound()
// 5
finishSendingMessage()
isTyping = false
}
private func observeMessages() {
// 1
let messagesQuery = messageRef.queryLimited(toLast: 25)
// 2
messagesQuery.observe(.childAdded) { (snapshot: FIRDataSnapshot!) in
// 3
let id = snapshot.value!["senderId"] as! String
let text = snapshot.value!["text"] as! String
// 4
self.addMessage(id: id, text: text)
// 5
self.finishReceivingMessage()
}
}
private func observeTyping() {
let typingIndicatorRef = rootRef.child("typingIndicator")
userIsTypingRef = typingIndicatorRef.child(senderId)
userIsTypingRef.onDisconnectRemoveValue()
// 1
usersTypingQuery = typingIndicatorRef.queryOrderedByValue().queryEqual(toValue: true)
// 2
usersTypingQuery.observe(.value) { (data: FIRDataSnapshot!) in
// 3 You're the only typing, don't show the indicator
if data.childrenCount == 1 && self.isTyping {
return
}
// 4 Are there others typing?
self.showTypingIndicator = data.childrenCount > 0
self.scrollToBottom(animated: true)
}
}
override func textViewDidChange(_ textView: UITextView) {
super.textViewDidChange(textView)
// If the text is not empty, the user is typing
isTyping = textView.text != ""
}
func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> AttributedString! {
return AttributedString(string:"test")
}
}
介意,所有这些代码都是用Swift 3编写的。
如果您能找到任何有助于我解决问题并最终让我的应用运行的内容,我将成为您最好的朋友。
提前致谢!
答案 0 :(得分:2)
Swift 3.0是目前处于测试阶段的开发者版本,预计将于2016年底发布。
某些库可能尚未提供,或者可能包含错误,因此您应立即重新安装最新的Swift公共稳定版本(目前编写v2.2)。
您自己说您已更新为Xcode的测试版。因此,我建议您重新下载Xcode from the Mac App Store并删除Xcode的测试版重新安装Swift 2.2。
对于Swift 3,请等到Apple于2016年秋季发布公开版本。然后,查看您的代码是否有效。
Firebase可能尚未更新其Swift 3.0库。
在此之前,我建议你继续使用Swift 2.2。由于兼容性错误,您不希望您的应用突然停止工作。
你说你下载了Xcode的测试版。我至少会等待Apple公司在2016年秋季发布Xcode的公开版本,然后重新尝试你的代码。
但是,我们不知道Firebase何时会更新其库。保留代码备份,并在备用机器中下载更新版本的Xcode。如果您的代码在备用计算机中正常运行,请在主计算机中下载。或者,安装VirtualBox等虚拟机,然后在那里试用您的应用。
答案 1 :(得分:1)
Swift 3
Firebase:如果您创建自己的密钥,它们必须是UTF-8编码的,最多可以是768字节,并且不能包含。,$,#,[,],/或ASCII控件字符0-31或127.
要处理它们,您需要用其他东西替换非firebase字符。
在String extension
用空格替换这些字符后,您可以选择自己的字符。 (例如' - ')
添加:
extension String {
func makeFirebaseString()->String{
let arrCharacterToReplace = [".","#","$","[","]"]
var finalString = self
for character in arrCharacterToReplace{
finalString = finalString.replacingOccurrences(of: character, with: " ")
}
return finalString
}
}
使用:
let searchString = "Super.Hero"
let firebaseSearchString = searchString.makeFirebaseString()
// firebaseSearchString is "Super Hero" now