"Cannot call value of non-function type"
Asked Answered
E

2

7

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

}
Embowel answered 22/7, 2016 at 23:35 Comment(11)
You can edit your post, so "delete and re-post" is not a good way. And, again, don't you have a property like var collectionView: JSQMessagesCollectionView! in your class?Somerville
Sorry about that. Something happened on my network and I thought something went wrong with my postEmbowel
Also, no I do not have any property like thatEmbowel
You are not showing the relevant code. You are saying JSQMessagesCollectionView somewhere but you are not showing us where.Firecure
Written in Objective-C where this was not an issue, the JSQMessagesViewController class has a property called collectionView, which is shadowing the collectionView() method. I don't know how to refer to one vs. the other clearly; in Swift you can't even define a property with the same name as a method.Beachhead
I have updated my post with my entire class for context. Also, this is JSQMessagesViewController: github.com/jessesquires/JSQMessagesViewControllerEmbowel
Remove let cell = super..., and init your cell properly.Unfleshly
@EvgenyKarkan, how would I init my cell properly?Embowel
Did you hear about reuse id technic?Unfleshly
@EvgenyKarkan no...Embowel
@Beachhead Do you have any ideas?Embowel
S
7

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.

Somerville answered 23/7, 2016 at 0:26 Comment(0)
U
0

Ok, this is how to create and reuse cell properly:

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

    //update cell subviews here 
    return cell
}

In your case you should create and return JSQMessagesCollectionViewCell instance

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("reuseId", forIndexPath: indexPath) as! JSQMessagesCollectionViewCell
Unfleshly answered 22/7, 2016 at 23:53 Comment(1)
How will this help me in the context of my problem?Embowel

© 2022 - 2024 — McMap. All rights reserved.