iosswiftjsqmessagesviewcontroller

Adding messages to a JSQCollectionView from another VC: Swift


To give a brief, I'm using JSQMessagesViewController for a chat based app. The normal adding of messages works fine. Now onto the problem, I'm using push notifications for receiving messages and storing them into core data. The thing I'm stuck at is the messages don't show up in chat instantly. Like if you refresh they will show but not at that exact moment.

Here's the code:

AppDelegate:

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (_ options: UNNotificationPresentationOptions) -> Void) {

    let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let messageVC = mainStoryboard.instantiateViewController(withIdentifier: "messageVC") as! messagesViewController

    if let incomingMessageSenderId = notification.request.content.userInfo["User_ID"] as? NSString {

        incomingMsgSenderId = String(incomingMessageSenderId)
    }
    if let message = notification.request.content.userInfo["Message"] as? String {

        msg = String(message)

    }

    DispatchQueue.main.async {

        messageVC.checkForMessages(id: incomingMsgSenderId)
    }

}

MessagesVC

func checkForMessages(id: String) {

    messages.removeAll()

    let context : NSManagedObjectContext = appDel.managedObjectContext

    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Nd_conversation")

    request.returnsObjectsAsFaults = false

    request.predicate = NSPredicate(format: "to_user_id = %@", id)

    do {
        let results = try context.fetch(request)

        if results.count > 0 {

            for result in results as! [NSManagedObject] {

                let conversation_id = result.value(forKey: "id")

                    let request2 = NSFetchRequest<NSFetchRequestResult> (entityName: "Nd_chat")
                    request2.returnsObjectsAsFaults = false

                    request2.predicate = NSPredicate(format: "conversation_id = %@", conversation_id! as! CVarArg)

                    do {

                        let results2 = try context.fetch(request2)

                        if results2.count > 0 {
                            for result2 in results2 as! [NSManagedObject] {

                                if let body = result2.value(forKey: "message_body") as? String {


                                    loadedMessages.append(body)

                                    if let sender_id = result2.value(forKey: "sender_id") as? Int {

                                        let sent_id = String(sender_id)

                                        print("Sender id: \(sent_id)")

                                        senderIds.append(sender_id)

                                        self.addMessage(sent_id, text: body)
                                      self.finishSendingMessage(animated: true)

                                    }


                                }
                                else if let imageData = result2.value(forKey: "media_path") as? NSData{
                                    //photo

                                    let image = UIImage(data: imageData as Data)

                                    let photoItem = JSQPhotoMediaItem(image: image)

                                    if let sender_id = result2.value(forKey: "sender_id") as? Int {

                                        let photoMessage = JSQMessage(senderId: String(sender_id), displayName: self.senderDisplayName, media: photoItem)

                                        messages.append(photoMessage!)

                                        self.finishSendingMessage(animated: true)
                                    }
                                }
                            }
                        }
                    }
            }
        }

Core data works fine. Even the messages do get appended to the messages array. The problem lies in the self.finishSendingMessage. Can anyone point out any suggestion as I'm stuck on this for a while. Thanks!


Solution

  • You can use notifications to observe and update changes in your VC.

    Create a Notification Name:

    extension Notification.Name {
        static let reload = Notification.Name("reload")
    }
    

    You can post a notification using:

    NotificationCenter.default.post(name: .reload, object: nil)
    

    And add an observer at the view controller that you want to reload the data:

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector:#selector(reloadTableData(_:)), name: .reload, object: nil)
    }
    
    func reloadTableData(_ notification: Notification) {
        tableView.reloadData()
    }