2016-07-23 61 views
3

我有一个应用程序使用Firebase在用户之间发送和接收消息。在将我的代码更新到新的Swift 3的过程中,我可以将iOS 10的酷炫新功能添加到我的应用程序中,但遇到了一些错误。我能够修复其中的大多数,除了这一个在运行时:使用Swift 3时'InvalidPathValidation'

Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(child:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']'' 

我不知道可能导致这一点。用户的用户ID在登录时被打印到控制台,但是一旦登录按钮被按下,我的应用就会崩溃。在我更新到Swift 3之前,这个错误并不存在,实际上只有在我修复了我的应用程序的另一部分中的错误后才出现。

无论如何,我的应用程序中只有两个主类:LoginViewControllerChatViewController

这里是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") 
    } 

} 

精神,所有这些代码是写在斯威夫特3.

如果您可以找到任何能够帮助我解决问题的东西,并最终让我的应用程序工作,我将成为您最好的朋友。

在此先感谢!

回答

2

雨燕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。至少我会等待苹果在2016年秋季发布Xcode的公共版本,然后再次尝试您的代码。

但是,我们不知道Firebase何时会更新其库。保留代码的备份,并在备用机器中下载更新版本的Xcode。如果您的代码在备用机器上正常工作,请将其下载到主机中。或者,安装虚拟机(如VirtualBox),然后在那里尝试您的应用程序。

+0

谢谢,是的,我认为这是一个失败的实验哈哈我最好的选择是回到什么可行,等待一个稳定的版本 –

+0

请[不要发布相同的答案多个问题](https://meta.stackexchange.com/q/104227)。发布一个很好的答案,然后投票/标记以重复关闭其他问题。如果问题不重复,*定制您对问题*的答案。 –

1

斯威夫特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