2016-07-23 38 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