1

I have been trying to build a chat app using JSQMessagesViewController with JSQDataSourcesKit to manage the data from Core Data. I have found several references to say that this is possible but I can't get it to work for me. I have the app building etc but when I try to load a message I get a crash:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JSQDataSourcesKit.BridgedDataSource collectionView:messageDataForItemAtIndexPath:]: unrecognized selector sent to instance 0x1024e49c0'

My code is:

import UIKit
import JSQMessagesViewController
import CoreData
import MagicalRecord
import JSQDataSourcesKit


@objc class MessagesViewController: JSQMessagesViewController,NSFetchedResultsControllerDelegate {

let delegate = UIApplication.sharedApplication().delegate as! AppDelegate

typealias MessageCellFactory = CellFactory<Message, JSQMessagesCollectionViewCell>
typealias MessageSupplementaryViewFactory = ComposedCollectionSupplementaryViewFactory<Message>
var dataSourceProvider: CollectionViewFetchedResultsDataSourceProvider<MessageCellFactory, MessageSupplementaryViewFactory>?

var delegateProvider: CollectionViewFetchedResultsDelegateProvider<MessageCellFactory>?

var frc : NSFetchedResultsController?

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    let user :NSDictionary = delegate.getMatchedUserForUsername(self.senderId)
    self.senderDisplayName = user.objectForKey("full_name") as! String;



    // 1. create cell factory
    let cellFactory = CellFactory(reuseIdentifier: "cell") { (cell, model: Message, collectionView, indexPath) -> JSQMessagesCollectionViewCell in

        cell.textView.text = model.text;
        return cell
    }



    // 2. create supplementary view factory
    let headerFactory = TitledCollectionReusableViewFactory(
        dataConfigurator: { (header, item: Message?, kind, collectionView, indexPath) -> TitledCollectionReusableView in

            return header
        },
        styleConfigurator: { (header) -> Void in
            header.backgroundColor = .darkGrayColor()
    })

    let footerFactory = TitledCollectionReusableViewFactory(
        dataConfigurator: { (footer, item: Message?, kind, collectionView, indexPath) -> TitledCollectionReusableView in

            return footer
        },
        styleConfigurator: { (footer) -> Void in
            footer.backgroundColor = .lightGrayColor()
            footer.label.font = .preferredFontForTextStyle(UIFontTextStyleFootnote)
            footer.label.textAlignment = .Center
    })

    let composedFactory = ComposedCollectionSupplementaryViewFactory(headerViewFactory: headerFactory, footerViewFactory: footerFactory)

    // 3. create fetched results controller
    frc = messageFRCinContext(NSManagedObjectContext.MR_defaultContext())

    // 4. create delegate provider
    delegateProvider = CollectionViewFetchedResultsDelegateProvider(collectionView: collectionView!,
                                                                    cellFactory: cellFactory,
                                                                    fetchedResultsController: frc!)

    // 5. create data source provider
    dataSourceProvider = CollectionViewFetchedResultsDataSourceProvider(fetchedResultsController: frc!,
                                                                        cellFactory: cellFactory,
                                                                        supplementaryViewFactory: composedFactory,
                                                                        collectionView: collectionView)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func collectionView(collectionView: JSQMessagesCollectionView!, messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
    let msg : Message = frc?.objectAtIndexPath(indexPath) as! Message
    let messageData = JSQMessage(senderId: msg.sender_jid, displayName: "", text: msg.text)
    return messageData
}

func messageFRCinContext(context: NSManagedObjectContext) -> NSFetchedResultsController {
    return  Message.MR_fetchAllSortedBy("sent_timestamp", ascending: false, withPredicate: nil, groupBy: nil, delegate: self)
}

}

It looks like the data source is being asked for a JSQMessageData conforming object but the CollectionViewFetchedResultsDataSourceProvider doesn't have the relevant method. How do I bridge the two together? Do I need to subclass a data source class maybe? Does anyone have this working?

Thanks.

Martin
  • 1,135
  • 1
  • 8
  • 19

0 Answers0