web-dev-qa-db-fra.com

"Impossible d'appeler une valeur de type non-fonction"

Je viens de télécharger la version bêta de Xcode 8 pour pouvoir inclure certains des nouveaux cadres iOS 10 dans mon application. Cependant, lors du processus de conversion de mon code de Swift 2 à Swift 3, plusieurs erreurs se sont produites. J'ai réparé tous sauf un super ennuyeux. 

Je reçois l'erreur:

Impossible d'appeler la valeur du type non-fonction 'JSQMessagesCollectionView!' à la ligne de code suivante:

let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! JSQMessagesCollectionViewCell

Voici toute ma fonction pour le contexte:

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
}

Quelqu'un a-t-il des idées?

P.s. Si cela aide, voici mon bloc de code entier:

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()

        // Change the navigation bar background color to blue.
        // navigationController!.navigationBar.barTintColor = UIColor.init(red:252/255, green: 87/255, blue: 68/255, alpha: 1)
        navigationController!.navigationBar.barTintColor = UIColor.init(red:250/255, green: 69/255, blue: 85/255, alpha: 1)


        title = "RoastChat"
        setupBubbles()
        // No avatars
        collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSize.zero
        collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSize.zero

        // Remove file upload icon
        self.inputToolbar.contentView.leftBarButtonItem = nil;

        messageRef = rootRef.child("messages")
    }

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

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

    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(
            // UIColor.init(red:250/255, green: 69/255, blue: 85/255, alpha: 1))
            with: UIColor.init(red:47/255, green: 53/255, blue: 144/255, alpha: 1))

        incomingBubbleImageView = factory?.incomingMessagesBubbleImage(
            with: UIColor.jsq_messageBubbleLightGray())
    }

    func addMessage(id: String, text: String) {
        let message = JSQMessage(senderId: id, displayName: "", text: text)
        messages.append(message!)
    }

    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
    }

    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(String(messageItem)) // 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)
        }
    }

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

}
6
Ahad Sheriff

Essayez de changer la méthode comme suit:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: NSIndexPath) -> UICollectionViewCell{
    let cell = super.collectionView(collectionView, cellForItemAt: 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
}

Si vous écrivez correctement une méthode remplacée, Swift se plaint de l'absence du mot clé override. Ainsi, si vous ne trouvez aucun avertissement ou erreur sur cette méthode substituée, vous utiliserez très probablement la signature de la méthode.

Et de nombreuses méthodes UICollectionViewDataSources sont renommées. Dans Swift3, "cellForItemAtIndexPath" a cette signature:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

Swift ne peut donc pas trouver une définition de méthode correspondant à collectionView(_:cellForItemAtIndexPath:). Par conséquent, en supposant que collectionView serait une propriété. (Malheureusement, il est déclaré dans JSQMessagesViewController.)

Vous pouvez avoir ce type d'implémentation de méthode incompatible dans votre classe. Mieux vaut tous les vérifier.

7
OOPer

Ok, voici comment créer et réutiliser une cellule correctement: 

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("reuseId", forIndexPath: indexPath) as! UICollectionViewCell

    //update cell subviews here 
    return cell
}

Dans votre cas, vous devez créer et renvoyer une instance JSQMessagesCollectionViewCell.

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("reuseId", forIndexPath: indexPath) as! JSQMessagesCollectionViewCell
0
Evgeny Karkan