ios - 使用 Swift 3 时的“InvalidPathValidation”

标签 ios swift firebase swift3 jsqmessagesviewcontroller

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

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

}

注意,所有这些代码都是用 Swift 3 编写的。

如果您能找到任何可以帮助我解决问题并最终让我的应用正常运行的东西,我将是您最好的 friend 。

提前致谢!

最佳答案

Swift 3.0 是目前处于测试阶段的开发者版本,预计将于 2016 年底发布。

一些库目前可能还不可用,或者可能包含错误,因此您应该立即重新安装最新的公开稳定版 Swift(目前为编写 v2.2)。

您自己说过您已更新到 Xcode 的测试版。因此,我建议您通过重新下载来重新安装 Swift 2.2 Xcode from the Mac App Store并删除 Xcode 的测试版。

对于 Swift 3,等到 Apple 在 2016 年秋季发布公共(public)版本。然后,看看您的代码是否有效。


Firebase 可能还没有为 Swift 3.0 更新它的库。

在此之前,我建议您继续使用 Swift 2.2。您不希望您的应用程序由于兼容性错误而突然停止工作。

您说您下载了 Xcode 的测试版。我至少会等待 Apple 在 2016 年秋季发布 Xcode 的公共(public)版本,然后再次尝试您的代码。

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

关于ios - 使用 Swift 3 时的“InvalidPathValidation”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38538626/

相关文章:

swift - 访问 tableView 单元格中的所有 UILabel 对象

objective-c - 如何在 Swift(或 ObjectiveC)中观察一个对象的所有类成员的变化?

javascript - ReactJS:为收集方法调用重新设置帮助文件管理器

swift - Swift中的角色游戏效果/药水生成器

android - FIRESTORE 持久数据

ios - Firebase 检查空值 (Swift)

ios - 无法子类化 UILabel : Unrecognized selector sent to UILabel

ios - SplitViewController 在使用之前应该在索引 0 处有一个 View Controller 吗?

objective-c - 为什么我得到 "unrecognized selector sent to instance"?

ios - 当应用程序 didFinishLaunching 时如何转到我想要的 Controller