"Cannot call value of non-function type"

Ahad Sheriff picture Ahad Sheriff · Jul 23, 2016 · Viewed 20.9k times · Source

I have just downloaded the Xcode 8 Beta so that I can include some of the new iOS 10 frameworks in my app. However, during the process of converting my code from Swift 2 to Swift 3, I ran into several errors. I fixed all but one super annoying one.

I am getting the error:

Cannot call value of non-function type 'JSQMessagesCollectionView!' at the following line of code:

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

Here is my entire function for context:

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
}

Does anybody have an ideas?

P.s. If this helps, here is my entire block of code:

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

}

Answer

OOPer picture OOPer · Jul 23, 2016

Try changing the method as:

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
}

If you are writing an overridden method correctly, Swift complains about missing override keyword. So, if you cannot find any warnings or errors on this overridden method, you are very likely misusing method signature.

And many UICollectionViewDataSources methods are renamed, in Swift3 "cellForItemAtIndexPath" has this signature:

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

So, Swift cannot find a method definition matching collectionView(_:cellForItemAtIndexPath:), so assuming the collectionView there would be a property. (Unfortunately, it is declared in JSQMessagesViewController.)

You may have this sort of mismatching method implementations in your class. Better check them all.