Swift - Getting double ?? error when working with UIImage - ios

I am having trouble working with images from Parse. I have created a function to take all image files from a Parse class, and save them into a dictionary (with key value being the objectId). Any idea why and/or how to fix? Below are the codes:
private func generateDictionaryOfImages(imageKeyToLookup: String, dictionaryKeyToReturn: String) {
for object in objectList {
var currentObjectId = object.objectId!
var image = UIImage()
let imageFile = object[imageKeyToLookup] as! PFFile
imageFile.getDataInBackgroundWithBlock({ (data: NSData?, error: NSError?) -> Void in
if data != nil {
if let imageData = data {
image = UIImage(data: imageData)!
}
}
})
// This imageDictionary is copied to the downloadedClientImages variable separately
self.imageDictionary[currentObjectId] = image
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Profile") as! ProfileTableViewCell
let title: String = grandCentral.returnValueForKeyAtIndexPath(indexPath.row, key: "forename") as! String
let currentUserId: String = grandCentral.returnCurrentUserId()
// Error is generated here. '#lvalue UIImage??' is not convertible to 'UIImage'
let image: UIImage = downloadedClientImages[currentUserId]
cell.setCell(title, image: image)
return cell
}

You need to unwrap optional after you access it from a dictionary.
if let image = downloadedClientImages[currentUserId] {
cell.setCell(title, image: image)
}

Related

UIImage returning nil from json request to mysql database for tableView cell image?

I am having trouble returning an image to the tableView cell.
When i change all the recipientImg parameters to string everything runs fine, but when I change the recipientImg parameters to UIImage I get (Data downloaded
fatal error: unexpectedly found nil while unwrapping an Optional value)
(lldb)
Ps i am trying to return the file path in the database as an image. The other two strings return in the tableView as strings but i cannot get the imageView to return the image.
Any Tips?
This is the JSON file on the server from the database
Also I'm using RecipientImg as [varchar] in the database
here is the viewermodel1.swift
import UIKit
class viewedMeModel1: NSObject {
//properties
var username: String?
var messageDetail: String?
var recipientImg: UIImage?
//empty constructor
override init()
{
}
//construct with parameters
init(username: String, messageDetail: String, recipientImg: UIImage) {
self.username = username
self.messageDetail = messageDetail
self.recipientImg = recipientImg
}
//prints object's current state
}
here is the viewedMeModel2.swift
import UIKit
protocol viewedMeModel2Protocol: class {
func itemsDownloaded(items: NSArray)
}
class viewedMeModel2: NSObject {
weak var delegate: viewedMeModel2Protocol!
var data = Data()
let urlPath: String = "http://" //this will be changed to the path where .php lives
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = viewedMeModel1()
//the following insures none of the JsonElement values are nil through optional binding
if let username = jsonElement["Username"] as? String,
let messageDetail = jsonElement["MessageDetail"] as? String,
let recipientImg = jsonElement["RecipientImg"] as? UIImage
{
location.username = username
location.messageDetail = messageDetail
location.recipientImg = recipientImg
}
locations.add(location)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: locations)
})
}
}
here is the viewedMeController.swift
import UIKit
class ViewerViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, viewedMeModel2Protocol {
var feedItems: NSArray = NSArray()
var selectedLocation : viewedMeModel1 = viewedMeModel1()
#IBOutlet weak var viewedMe: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.viewedMe.delegate = self
self.viewedMe.dataSource = self
let ViewedMeModel2 = viewedMeModel2()
ViewedMeModel2.delegate = self
ViewedMeModel2.downloadItems()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.viewedMe.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return feedItems.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of feed items
return feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Retrieve cell
let cellIdentifier: String = "basicCell"
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
// Get the location to be shown
let item: viewedMeModel1 = feedItems[indexPath.row] as! viewedMeModel1
// Get references to labels of cell
cell.UIImage?.image = item.recipientImg!
return cell
}
The problem is with your viewedMeModel2.swift, at this line:
let recipientImg = jsonElement["RecipientImg"] as? UIImage
the conditional unwrapped result will alway return recipientImg = nil, because jsonElement["RecipientImg"] is a string, it cannot be casted to UIImage.
You should rewrite your code to this:
if let username = jsonElement["Username"] as? String,
let messageDetail = jsonElement["MessageDetail"] as? String,
let recipientImgString = jsonElement["RecipientImg"] as? String
{
location.username = username
location.messageDetail = messageDetail
location.recipientImg = UIImage(named: recipientImgString)
}
My guess is that jsonElement["RecipientImg"] is returning a String not a UIImage, so you're getting nil because you can't cast the string as an image. Trying getting an image url from jsonElement["RecipientImg"] and then create a UIImage from that url. Something like this:
let imageURL = jsonElement["RecipientImg"] as? String
let myImage = UIImage(contentsOfFile: imageURL)
You can also use the UIImage initializer init?(data: Data) if you're getting some sort of data object.
Again, the object at jsonElement["RecipientImg"] probably can't be cast to UIImage, and my guess is that it's a String. Find out what it is and what you can cast it as, and then use the appropriate UIImage initializer from the documentation.
https://developer.apple.com/documentation/uikit/uiimage

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!
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
I would suggest trying to isolate your problems. I don't know if the issue is with JSQMessagesAvatarImageFactory I think the issue may be that you do not have the image downloaded by the time the cell needs to be displayed. I would make sure that you are getting something back from fireBase before you try and set it to your avatar. A closure is normally how I do this something like
func getImageForUser(id: String, completiion() -> Void) {
//Add your logic for retrieving from firebase
let imageFromFirebase = firebaserReference.chiledWithID(id)
completion(image)
}
Then in your
override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
var avatarImage = JSQAavatarImage()
getImageForUser {
self.avatarImage = JSQMessagesAvatarImageFactory.avatarImageWithPlaceholder(imageFromFirebase, diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
self.collectionView.reloadItemAtIndexPath(indexPath)
}
That way it waits till the response is back and then reloads the cell once it is there.
Let me know if you have any other questions.

Image url shows error while calling to display image in UITableview

I have stored the json image url in a array but while calling the url it shows error
Model class
import Foundation
class ProductDetails {
var productAuthor: String!
var productPrice: Int!
var artImages: [ArtImage]!
}
class ArtImage {
var imagepath: String!
var imgvideotype: Int!
}
TableView Controller Storage variable
var globalArr = [ProductDetails]()
Parsing function
func parseJSONData(data: NSData) -> [ProductDetails] {
var product_Detail = [ProductDetails]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
let jsonProductDetails = jsonResult?["data"] as! [AnyObject]
//print("the json response is",jsonProductDetails)
for jsonproductDetail in jsonProductDetails{
let productDetail = ProductDetails()
// let jsonProductImageDetails = jsonProductDetails["images"] as! [AnyObject]
productDetail.productAuthor = jsonproductDetail["first_name"]as! String
productDetail.productPrice = jsonproductDetail["prodprice"]as! Int
// Getting inside the json
let jsonProductImageDetails = jsonproductDetail["images"] as! [AnyObject]
var artImagesModelArray = [ArtImage]()
for image in jsonProductImageDetails {
let artImage = ArtImage();
artImage.imagepath = image["imagepath"] as! String
artImage.imgvideotype = image["imgvideotype"] as! Int
artImagesModelArray.append(artImage)
}
productDetail.artImages = artImagesModelArray;
product_Detail.append(productDetail)
}
}
catch {
print (error)
}
return product_Detail
}
Tableview DataSource
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! UserHomeScreenTableViewCell
// Configure the cell...
cell.artsAuthorName.text = globalArr[indexPath.row].productAuthor
cell.priceLabel.text = "\(globalArr[indexPath.row].productPrice)"
let productDetailsObject = globalArr[indexPath.row].artImages
print("#################",productDetailsObject)
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
if let url = (NSURL(string: self.globalArr[indexPath.row])) {
//The error comes here....in self.global array
if let data = NSData(contentsOfURL: url) {
if let image = UIImage(data: data) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
cell.artImageView.image = image
}
}
}
}
})
return cell
}
Here i have stored the parse json and display some details in tableview cell upto here everything works fine .
but call async way to load images from array its shows error
any suggestion ..plz..
Thank you
You need to change the way how you're taking the image url from the ProductDetails.
I guess you need to use something like this:
if let url = NSURL(string: self.globalArr[indexPath.row].artImages[imageIndex].imagepath) { // your code }
Because when you perform
if let url = (NSURL(string: self.globalArr[indexPath.row]))
you get an object of ProductDetails, but not an image url.

How to load image from url which I got via API calling

I want to use UICollectionView for displaying the images and I am getting that images by api calling.
Question: so I am getting images path via api calling so how can I display it to UICollectionView??
here is my code ::
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
cell.imagev.image = dic["image"] as? UIImage
return cell
}
and here is my api response
(
{
image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/esquire.jpg";
slug = esquire;
},
{
image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/forbes.jpg";
slug = forbes;
},
{
image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/tapas.jpg";
slug = tapas;
}
)
so how can I display this images in my UICollectionView
UPDATE:: While using commented code getting strange issue i am calling my webservice in viewdidload
override func viewDidLoad() {
super.viewDidLoad()
webimages()
// Do any additional setup after loading the view, typically from a nib.
}
and its started to call webservice
func webimages()
{
let url = "http://radio.spainmedia.es/podcasts/"
request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
print(response.result.value)
self.imagearray = (response.result.value) as! NSMutableArray
print(self.imagearray)
}
}
but after requesting its suddenly go to cellForItemAtIndexPath so my "imagearray" found nil there. and then its comeback to webimages() and giving me api response.
So how can I solve this?
we have array of string we are passing single string here so can you please tell me that what is the solution
We have array of string we are passing single string here so can you please tell me that what is the solution
enter image description here
You are setting a URL string as UIImage. You first have to retrieve image from that URL first. Use the following method for quick remedy:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
if imagearray.count > 0
{
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let imgURL: NSString = dic!["image"] as! NSString //Get URL string
let url = NSURL.URLWithString(imgURL); //Create URL
var err: NSError?
var imageData :NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)! //Fetch Image Data
var cellImage = UIImage(data:imageData) //Create UIImage from Image data
cell.imagev.image = cellImage //Set image
}
return cell
}
Notice that this is fetching content of image URL in a synchronous call so that would freeze your UI until download completes. Also this is not caching the Image so images will be downloaded over and over again when you scroll and cells are recreated. To avoid that I'd suggest caching .
For better results, This is how you load image asynchronously, without freezing the UI and cache the images to avoid network load.
You first have to create a class first like this:
class ImageLoader {
var cache = NSCache() //Create cache
class var sharedLoader : ImageLoader {
struct Static {
static let instance : ImageLoader = ImageLoader()
}
return Static.instance
}
func imageForUrl(urlString: String , indexPathArg:NSIndexPath!, completionHandler:(image: UIImage?, url: String,indexPathResponse:NSIndexPath?) -> ()) {
let currentIndexPath: NSIndexPath! = indexPathArg.mutableCopy() as! NSIndexPath
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in
let data: NSData? = self.cache.objectForKey(urlString) as? NSData
//Check if image data for this URL already exists in Cache
if let goodData = data {
//data exists, no need to download it again. Just send it
let image = UIImage(data: goodData)
dispatch_async(dispatch_get_main_queue(), {() in
completionHandler(image: image, url: urlString,indexPathResponse: currentIndexPath)
})
return
}
//Data does not exist, We have to download it
let downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!,completionHandler: { (data: NSData?, response:NSURLResponse?, error: NSError?) -> Void in
if (error != nil) {
//Download failed
completionHandler(image: nil, url: urlString, indexPathResponse: currentIndexPath)
return
}
if data != nil {
//Download successful,Lets save this downloaded data to our Cache and send it forward as UIImage
let image = UIImage(data: data!)
self.cache.setObject(data!, forKey: urlString)
dispatch_async(dispatch_get_main_queue(), {() in
completionHandler(image: image, url: urlString, indexPathResponse: currentIndexPath)
})
return
}
})
downloadTask.resume()
})
}
}
Then you have to modify your collectionview delegate like this:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
if imagearray.count > 0
{
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let imgURL: NSString = dic!["image"] as! NSString//Get URL string
ImageLoader.sharedLoader.imageForUrl(imgURL as String,indexPathArg: indexPath, completionHandler:{(image: UIImage?, url: String, indexPathResponse: NSIndexPath?) in
let indexArr:NSArray = collectionView!.indexPathsForVisibleItems()
if indexArr.containsObject(indexPathResponse!)
{
cell.imagev.image = image //Set image
}
})
}
return cell
}
Now it will load your image asynchronously and will download it only if necessary. Great Success! (To quote Borat). I have added comments so that you can understand What's going on in my code and Daniel's code :)
To Fix your crash issue which is not a part of your original question and instead a different problem you created, Return count of items in section to be count of your image array and reload collectionview once you have retrieved your data:
func webimages()
{
let url = "http://radio.spainmedia.es/podcasts/"
request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
print(response.result.value)
self.imagearray = (response.result.value) as! NSMutableArray
print(self.imagearray)
//Reload Collection view
self.collectionView?.reloadData()
}
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagearray.count
}
Credits for Imageloader class: Daniel Sattler
Special Thanks to: CouchDeveloper
Pretty easy you got to downlaod the image from that url and set it as the image for the image view,
Try this, https://github.com/natelyman/SwiftImageLoader
Add the ImageLoader class to your project and modify the collectionview data source as below,
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
//cell.imagev.image = dic["image"] as? UIImage
ImageLoader.sharedLoader.imageForUrl(dic["image"], completionHandler: {(image: UIImage?, url: String) in
cell.imagev.image = image
})
return cell
}
This is an asynchronous image loading class so UI would not freeze or give you any other problems if you are against using any third party libs or classes please do it manually as #NSNoob 's answer.
Other good image loading libraries are,
https://github.com/nicklockwood/AsyncImageView
https://github.com/onevcat/Kingfisher
https://github.com/MengTo/Spring/blob/master/Spring/AsyncImageView.swift
https://github.com/anas10/AsyncImageView-Swift
You can extend UIImageView as following -
extension UIImageView {
public func imageFromU(urlString: String) {
if let url = NSURL(string: urlString) {
let request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
if let imageData = data as NSData? {
self.image = UIImage(data: imageData)
}
}
}
}
}
Then in any UIImageView you will have a very simple helper method as follows -
yourImageView.imageFromURL("https://yoururl.com/image.png")
And in your case
cell.imagev.image.imageFromURL(dic["image"])
if let url = NSURL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") {
if let data = NSData(contentsOfURL: url){
imageURL!.contentMode = UIViewContentMode.ScaleAspectFit
imageURL!.image = UIImage(data: data)
}
}

Parse - imageView as PFFile won't load

I don't understand what is going on. I have an image saved as a PFFile in Parse. I can see it and I know it is there. I want to have it as a cell image. The rest of the code below works fine and the memory addresses of PFFile also print. textLabel and detailTextLabel also fine but the images won't show (even if I delete 'loadInBackground'). Any ideas?
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! PFTableViewCell!
if cell == nil {
cell = PFTableViewCell(style: .Subtitle, reuseIdentifier: "Cell")
}
if let name = object?["name"] as? String {
cell.textLabel?.text = name
}
if let artist = object?["artist"] as? String {
cell.detailTextLabel?.text = artist
}
if let artwork = object?["artwork"] as? PFFile {
println("we've got an artwork image \(artwork)")
//cell!.imageView!.image = UIImage(named: "placeholder.jpg")
cell.imageView?.file = artwork
cell.imageView?.loadInBackground()
}
return cell
}
Parse just saves an reference to the image in the table, you will have to do another async call to retrieve the message.:
let artwork = object?["artwork"] as PFFile
artwork.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
}
}
}

Resources