Ahad Sheriff Ahad Sheriff - 4 months ago 50
Swift Question

"Cannot call value of non-function type"

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

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
Comments