7

Recently I have been developing a chat application and was having trouble asynchronously loading images with the chat.

Working with MessageKit - 2.0

I had tried this

import MessageKit

class Image: MediaItem {
  var url: URL?

  var image: UIImage?

  var placeholderImage: UIImage

  var size: CGSize

  init(url: URL) {
    self.url = url
    self.size = CGSize(width: 240, height: 240)
    self.placeholderImage = UIImage()
    DispatchQueue.global().async {
        if let data = try? Data(contentsOf: url) {
            if let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.image = image
                }
            }
        }
    }
}

init(image: UIImage) {
    self.image = image
    self.size = CGSize(width: 240, height: 240)
    self.placeholderImage = UIImage()
}

}

Then I initialize the Image MessageType with kind = .photo(Image(url: url))

This doesn't seem to work.

Paul Nyondo
  • 2,126
  • 2
  • 23
  • 30

2 Answers2

16

I have since learnt that MessageKit provides a delegate method in MessagesDisplayDelegate called

func configureMediaMessageImageView(_ imageView: UIImageView,
                                    for message: MessageType,
                                    at indexPath: IndexPath,
                                    in messagesCollectionView: MessagesCollectionView)

We can asynchronously load images for given message with this delegate method.

I am using a UIImageView extension to help with this

import UIKit

extension UIImageView {
  func load(url: URL) {
    DispatchQueue.global().async { [weak self] in
        if let data = try? Data(contentsOf: url) {
            if let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self?.image = image
                }
            }
        }
     }
   }
 }

So the solution is as follows

func configureMediaMessageImageView(_ imageView: UIImageView,
                                    for message: MessageType,
                                    at indexPath: IndexPath,
                                    in messagesCollectionView: MessagesCollectionView) {
    /*acquire url for the image in my case i had a 
    custom type Message which stored  the image url */
    guard
        let msg = message as? Message,
        let url = msg.downloadURL
    else { return }
    imageView.load(url: url)
}
Paul Nyondo
  • 2,126
  • 2
  • 23
  • 30
  • This works, what I ended up adding was a `messageImage` property to `Message`, so once the image is downloaded I stored it there and then check for that property to avoid unnecessary request to download the image. – Lucho Jun 17 '19 at 15:47
  • Thank you, Paul and Lucho. I was having difficulties trying to make images download async in MessageKit's VC. I've taken both of your suggestions and implemented the logic in my app. Works like a charm! – fishhau Nov 07 '19 at 13:31
  • That is the solution! – Ankur Lahiry Nov 24 '19 at 07:06
  • @Paul I'm working on the same problem. Would you be open to chat? – techgirl Mar 11 '20 at 00:42
  • Any way to set the image size after the async download? I'd rather not have it fixed to something like 240, 240. – Nimeton Dec 20 '21 at 06:03
0

Safer way to what @Paul Nyondo provided. Getting and setting image from a URL while accessing message item data (MessageType) and no need to check if is a type of 'Message'.

1.- Go to your file when you add delegates of "MessagesDisplayDelegate" and add this method:

func configureMediaMessageImageView(_ imageView: UIImageView,
                                    for message: MessageType,
                                    at indexPath: IndexPath,
                                    in messagesCollectionView: MessagesCollectionView) {
    if case let .photo(mediaItem) = message.kind, let imageURL = mediaItem.url {
        imageView.kf.setImage(with: imageURL)
    }
}

2.- Helper method to download image in an async way:

import UIKit

extension UIImageView {
  func load(url: URL) {
    DispatchQueue.global().async { [weak self] in
        if let data = try? Data(contentsOf: url) {
            if let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self?.image = image
                }
            }
        }
     }
   }
 }
Egzon P.
  • 4,498
  • 3
  • 32
  • 31