致命错误:在展开可选值错误时意外发现nil

时间:2016-04-27 02:23:01

标签: swift runtime-error exc-bad-instruction

我正在尝试使用swift处理聊天应用程序,当我在运行期间构建并运行项目时,当我尝试访问ChatVewController时,它会显示此EXC错误指令错误。

控制台说

致命错误:在解开可选值时意外发现nil。

这是我的代码。

import UIKit
import Firebase

class SportsLogin: UIViewController {

// MARK: Properties
let ref: Firebase  = Firebase(url: BASE_URL2)


override func viewDidLoad() {
super.viewDidLoad()
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)

let navVC2 = segue.destinationViewController as! UINavigationController
let chatVC2 = navVC2.viewControllers.first as! SportsViewController

chatVC2.senderId = ref.authData.uid // Assign the local user’s ID to chatVc.senderId; this is the local ID that JSQMessagesViewController uses to coordinate messages.
chatVC2.senderDisplayName = "" // chatVc.senderDisplayName is set to empty string, since this is an anonymous chat room.
}



@IBAction func loginDidTouch(sender: AnyObject) {

ref.authAnonymouslyWithCompletionBlock { (error, authData) -> Void in
    if error != nil {  // Check for an authentication error.
        print(error.description)
        return
    }
    // Inside of the closure, trigger the segue to move to ChatViewController.
    print(self.ref.authData)
    self.performSegueWithIdentifier("SportChat", sender: self)
}

}

}

错误的行是

chatVC2.senderId = ref.authData.uid // Assign the local user’s ID to   chatVc.senderId; this is the local ID that JSQMessagesViewController uses to coordinate messages.

谢谢!

这是我的SportsViewController代码。

import UIKit
import Firebase
import JSQMessagesViewController

class SportsViewController: JSQMessagesViewController {

// MARK: Properties
var messages = [JSQMessage]() // messages is an array to store the various instances of JSQMessage

var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!

// MARK: Firebase refs
// In case you’re wondering, creating another reference doesn’t mean you’re creating another connection. Every reference shares the same connection to the same Firebase database.
let rootRef = Firebase(url: BASE_URL2)
var messageRef = Firebase()

var userIsTypingRef: Firebase! // reference that tracks whether the local user is typing
var usersTypingQuery: FQuery!  // FQuery, which is just like a Firebase reference, except that it’s ordered by an order function.

// Typing tracking related properties
private var localTyping = false // Store whether the local user is typing in a private property
var isTyping: Bool {
    get {
        return localTyping
    }
    set {
        // Using a computed property, update userIsTypingRef each time user updates this property.
        localTyping = newValue
        userIsTypingRef.setValue(newValue)
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    title = "NBA Chat"
    setupBubbles()

    // No avatars
    collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
    collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero

    messageRef = rootRef.childByAppendingPath("messages")
}


override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.observeMessages()
    self.observeTyping()
}


override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)

    messageRef.removeAllObservers()
}


private func setupBubbles() {
    // JSQMessagesBubbleImageFactory has methods that create the images for the chat bubbles. There’s even a category provided by JSQMessagesViewController that creates the message bubble colors used in the native Messages app.
    let factory = JSQMessagesBubbleImageFactory()
    outgoingBubbleImageView = factory.outgoingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleBlueColor())
    incomingBubbleImageView = factory.incomingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleLightGrayColor())
}


// MARK: JSQMessagesCollectionView Datasource
override func collectionView(collectionView: UICollectionView,
    numberOfItemsInSection section: Int) -> Int {
        return messages.count
}

override func collectionView(collectionView: JSQMessagesCollectionView!,
    messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
        return messages[indexPath.item]
}

override func collectionView(collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {

    let message = messages[indexPath.item] // retrieve the message based on the NSIndexPath item.
    if message.senderId == senderId { // Check if the message was sent by the local user. If so, return the outgoing image view.
        return outgoingBubbleImageView
    } else {  // If the message was not sent by the local user, return the incoming image view.
        return incomingBubbleImageView
    }
}

// set text color based on who is sending the messages
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! JSQMessagesCollectionViewCell

    let message = messages[indexPath.item]

    if message.senderId == senderId {
        cell.textView!.textColor = UIColor.whiteColor()
    } else {
        cell.textView?.textColor = UIColor.blackColor()
    }


    return cell
}



// remove avatar support and close the gap where the avatars would normally get displayed.
override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
    return nil
}


// MARK: - Create Message
// This helper method creates a new JSQMessage with a blank displayName and adds it to the data source.
func addMessage(id: String, text: String) {
    let message = JSQMessage(senderId: id, displayName: "", text: text)
    messages.append(message)
}

// SEND button pressed
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: NSDate!) {

    let itemRef = messageRef.childByAutoId() // Using childByAutoId(), you create a child reference with a unique key.
    // Create a dictionary to represent the message. A [String: AnyObject] works as a JSON-like object
    let messageItem = ["text": text, "senderId": senderId]

    itemRef.setValue(messageItem) // Save the value at the new child location.

    // Play the canonical “message sent” sound.
    JSQSystemSoundPlayer.jsq_playMessageSentSound()

    // Complete the “send” action and reset the input toolbar to empty.
    finishSendingMessage()

}

// Observer logic
private func observeMessages () {

    // Start by creating a query that limits the synchronization to the last 25 messages.
    let messagesQuery = messageRef.queryLimitedToLast(25)

    // Use the .ChildAdded event to observe for every child item that has been added, and will be added, at the messages location.
    messagesQuery.observeEventType(FEventType.ChildAdded) { (snapshot:FDataSnapshot!) -> Void in

        // Extract the senderId and text from snapshot.value.

        if let id = snapshot.value["senderId"] as? String, text = snapshot.value["text"] as? String {

            // Call addMessage() to add the new message to the data source.
            self.addMessage(id, text: text)

            // Inform JSQMessagesViewController that a message has been received.
            self.finishReceivingMessage()

        }

    }

}

// observer user typing object from Firebase
private func observeTyping() {
    // This method creates a reference to the URL of /typingIndicator, which is where you’ll update the typing status of the user. You don’t want this data to linger around after users have logged out, so you can delete it once the user has left using onDisconnectRemoveValue().

    let typingIndicatorRef = rootRef.childByAppendingPath("typingIndicator")
    userIsTypingRef = typingIndicatorRef.childByAppendingPath(senderId)
    userIsTypingRef.onDisconnectRemoveValue()


    // initialize the query by retrieving all users who are typing. This is basically saying, “Hey Firebase, go to the key /typingIndicators and get me all users for whom the value is true.”
    usersTypingQuery = typingIndicatorRef.queryOrderedByValue().queryEqualToValue(true)

    // Observe for changes using .Value; this will give you an update anytime anything changes.
    usersTypingQuery.observeEventType(FEventType.Value) { (data:FDataSnapshot!) -> Void in

        // You're the only typing, don't show the indicator
        if data.childrenCount == 1 && self.isTyping {
            return
        }

        // Are there others typing?
        self.showTypingIndicator = data.childrenCount > 0
        self.scrollToBottomAnimated(true)
    }


}



// Mark: textView delegate
override func textViewDidChange(textView: UITextView) {
    super.textViewDidChange(textView)

    // If the text is not empty, the user is typing
    isTyping = textView.text != ""

}



}

这是我声明了senderId的viewcontroller。

import UIKit

struct Message {

let text: String!
let senderId: String!




}

0 个答案:

没有答案