LEVIS OGCPAS LEVIS OGCPAS - 4 months ago 71
iOS Question

Swift - JSQMessagesViewController with Swift

I'm developing a chat app, I'm having problem showing the Avatar to my

JSQMessagesViewController


override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {

var avatar = UIImage()

let people = FIRDatabase.database().reference().child("people").child(senderId)
people.observeEventType(.Value, withBlock: {
snapshot -> Void in
let dict = snapshot.value as! Dictionary<String, AnyObject>
let imageUrl = dict["profileImage"] as! String
if imageUrl.hasPrefix("gs://") {
FIRStorage.storage().referenceForURL(imageUrl).dataWithMaxSize(INT64_MAX, completion: { (data, error) in
if let error = error {
print("Error downloading: \(error)")
return
}
avatar = UIImage.init(data: data!)!

})
}
})

let AvatarJobs = JSQMessagesAvatarImageFactory.avatarImageWithPlaceholder(avatar, diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))

return AvatarJobs
}


The problem here is, when I'm trying to pull the image of the sender from firebase, I'm getting a blank image, but when i try to use this
let AvatarJobs = JSQMessagesAvatarImageFactory.avatarImageWithPlaceholder(UIImage(named: "icon.png"), diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
it's working fine, What do you think is the problem here? Thanks!

Answer

If I may suggest an alternative? Why don't you have a dictionary:

var avatars = [String: JSQMessagesAvatarImage]()

let storage = FIRStorage.storage()

And use the following function:

override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource!
{
    let message = messages[indexPath.row]
    return avatars[message.senderId]
}

And create the avatars in viewDidLoad (or where ever )

createAvatar(senderId, senderDisplayName: senderDisplayName, user: currentUser,  color: UIColor.lightGrayColor())

with a function

func createAvatar(senderId: String, senderDisplayName: String,  user: FBUser, color: UIColor)
{
    if self.avatars[senderId] == nil
    {
        //as you can see, I use cache
        let img = MyImageCache.sharedCache.objectForKey(senderId) as? UIImage

        if img != nil
        {
            self.avatars[senderId] = JSQMessagesAvatarImageFactory.avatarImageWithImage(img, diameter: 30)

            // print("from cache")
        }
        else if let photoUrl = user.pictureURL where user.pictureURL != ""
        {
       // the images are very small, so the following methods work just fine, no need for Alamofire here

            if photoUrl.containsString("https://firebasestorage.googleapis.com")
            {
                self.storage.referenceForURL(photoUrl).dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
                    if (error != nil)
                    {
                        //deal with error
                    }
                    else
                    {
                        let newImage = UIImage(data: data!)

                        self.avatars[senderId] = JSQMessagesAvatarImageFactory.avatarImageWithImage(newImage, diameter: 30)

                        MyImageCache.sharedCache.setObject(newImage!, forKey: senderId, cost: data!.length)
                    }
                }
            }
            else if let data = NSData(contentsOfURL: NSURL(string:photoUrl)!)
            {
                let newImage = UIImage(data: data)!

                self.avatars[senderId] = JSQMessagesAvatarImageFactory.avatarImageWithImage(newImage, diameter: 30)

                MyImageCache.sharedCache.setObject(newImage, forKey: senderId, cost: data.length)
            }
            else
            {
                //etc. blank image or image with initials
            }
        }
    }
    else
    {
        //etc. blank image or image with initials
    }
}

for Cache I have a custom class

import Foundation

class MyImageCache
{
    static let sharedCache: NSCache =
    {
        let cache = NSCache()
        cache.name = "MyImageCache"
        cache.countLimit = 200 // Max 200 images in memory.
        cache.totalCostLimit = 20*1024*1024 // Max 20MB used.
        return cache
    }()
}

Let me know if that helps