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.