I am wondering if I have done anything wrong here.
I have a subclass of PFUser which has a property of profileImage, which is a PFFile
There are some cases when I don't save the profileImage right away to Parse and I only pin it to the localDatastore.
But when I tried to retrieve it back from the localDataStore and use the getDataInBackgroundWithBlock. It does not return any error, but the NSData returned by the callback is always nil.
if let profileImage = PGUser.currentUser()?.profileImage {
profileImage.getDataInBackgroundWithBlock { (data: NSData?, error: NSError?) -> Void in
if error == nil {
if data != nil {
println("IMAGE DATA FOUND")
let image = UIImage(data: data!);
self.profileImageView.image = image;
}
else {
//DATA IS ALWAYS NIL
println("NO IMAGE DATA FOUND")
}
}
}
}
The PGUser.currentUser()?.profileImage is NOT NIL
No error returned by the getDataInBackgroundWithBlock function.
BUT the data is always
NIL.
Any thoughts on what am I doing wrong?
Thank you!!
Try this. I solved my problem with this
let profileImage = userPhoto["imageFile"] as PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if !error {
let image = UIImage(data:imageData)
self.profileImageView.image = image
}
}
Related
How do i convert an PFFile to an UIImage with swift?
In this code, the app is getting the file from parse and now i want it to show on a UIImageView, But i get an error...
Here is my code...
var ImageArray:UIImage = [UIImage]()
var textArray:String = [String]()
var query = PFQuery(className:"ClassName")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects as? [PFObject] {
for object in objects {
//this works fine
self.textArray.append(object.valueForKey("Image")! as! String)
//this does not work...
self.ImageArray.append(object.valueForKey("Image")! as! PFFile)
//I get an error that says PFFile is not convertible to UIImage. How do i convert it?
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
PFFile is a parse representation of anykind of file. To get the "real" file (image), you need to call getDataInBackgroundWithBlock. Try it:
if let userPicture = object.valueForKey("Image")! as! PFFile {
userPicture.getDataInBackgroundWithBlock({
(imageData: NSData!, error NSError!) -> Void in
if (error == nil) {
let image = UIImage(data:imageData)
self.ImageArray.append(image)
}
})
}
Swift 1.2+ Version
if let userPicture = PFUser.currentUser()!.valueForKey("Image") as? PFFile {
userPicture.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let image = UIImage(data:imageData!)
self.ImageArray.append(image)
}else{
print("Error: \(error)")
}
}
}
With Swift 3 on Parse.
if let photo = obj.file as? PFFile {
photo.getDataInBackground(block: {
PFDataResultBlock in
if PFDataResultBlock.1 == nil {//PFDataResultBlock.1 is Error
if let image = UIImage(data:PFDataResultBlock.0!){
//PFDataResultBlock.0 is Data
photoCell.attachedPicture.image = image
}
}
})
}
The line in question is "let productImageFile = productData!["productImage"] as! PFFile" which gives me the error "fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)". The only answers I've found have involved making sure I am not trying to unwrap explicitly defined optionals (I think that's the term), but I messed around with the optionals, and which I unbind and when, but I'm having no luck. No other source has been able to solve this specific issue for me and I'm stuck. Please help.
override func viewDidLoad() {
super.viewDidLoad()
//Create new PFQuery to retrieve info from Parse
var query: PFQuery = PFQuery(className: "MyProduct")
//function to get the data
func getProductData (){
//call function to get the data from parse by specifyng an objectId
query.getObjectInBackgroundWithId("XXXXXXXXXX") {
(productData:PFObject?, error:NSError?) -> Void in
if error == nil && productData != nil {
//Extract values from the productData PFObject and store them in constants
let dayOfTheWeek = productData!.objectForKey("day") as! String
let productTitle = productData!.objectForKey("productTitle") as! String
//-----start image loading
let productImageFile = productData!["productImage"] as! PFFile
productImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
self.productImageView.image = image!
} else {println("Could not load image.")}
}
}
//-----end image loading
let productPrice = productData!.objectForKey("productPrice") as! String
let productDescription = productData!.objectForKey("productDescription") as! String
//take the saved constants and assign their values to the labels and UIImage on screen
self.productTitleLabel.text = productTitle
self.dayOfTheWeekLabel.text = dayOfTheWeek
self.productPriceLabel.text = productPrice
self.productDescriptionLabel.text = productDescription
} else if error != nil {
println("Could not load data from Parse")
}
}
}
I assume not for all products you have an image, so you need to update your code as following:
if let productImageFile = productData!["productImage"] as? PFFile {
productImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
self.productImageView.image = image!
} else {println("Could not load image.")}
}
}
}
This will guarantee that productImageFile will be processed only if response of productImage is PFFile.
Ensure you are getting valid data if your error is not printing anything useful. Check the data length and see if it corresponds to the file size.
Also, check to see if the imageView is setting the image on the main thread, it will not show if called from a background thread.
dispatch_async(dispatch_get_main_queue(), ^ {
self.productImageView.image = image!
}
I am trying to display an image from parse using swift. This is my code:
var query = PFQuery(className: "Maps")
query.getObjectInBackgroundWithId("1234asdf3456") {
(object: PFObject?, error: NSError?) -> Void in
if error == nil
{
println(object)
var objectAsPF = object as PFObject!
let file = objectAsPF["imageFile"] as! PFFile
file.getDataInBackgroundWithBlock {
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let map:UIImage = UIImage(data: imageData)!
self.MapView.image = map
println("success")
}
}
}
}
else
{
println(error)
}
}
I set a breakpoint at println("success") and i checked the variable values and everything is fine until i try to convert imageData to UIImage. Any tips?
Use this code to retrieve images from parse then convert it from a PFFile to a UIImage...
var query = PFQuery(className:"Maps")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
self.scored = objects!.count
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
let userImageFile = object["imageFile"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
if image != nil {
self.imageArray.append(image!)
}
}
}
}
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
dispatch_async(dispatch_get_main_queue()) {
println("Finished Loading Image")
}
I have a PFQueryTableViewController populated by comments from different users. Each user has a profile picture stored on the Parse database. After loading each comment into a cell, I query the PFUser class to retrieve the profile picture of the user who posted the comment and add it to the cell. I also use PFCachePolicy to cache the profile picture to the device's memory so that displaying new cells with new profile pictures is a smoother transition.
However this is not the case. When a user posts a new comment and a new cell is added, the profile pictures shuffle around and takes about two seconds or so to update with the right image (probably because the table is re-queried and updated). I am trying to achieve something similar to iMessage or WhatsApp where the profile picture remained 'fixed' in the cell.
I am not sure what the problem is or if there is a better way to do this?
// get objectId of the user who posted a comment
let senderId = object?["Users"]!.objectId as String!
// query PFUser class using senderId to retrieve profile picture
var senderImage:PFQuery = PFUser.query()!
senderImage.cachePolicy = PFCachePolicy.CacheThenNetwork
senderImage.getObjectInBackgroundWithId(senderId){
(sender: PFObject?, error: NSError?) -> Void in
if error == nil && sender?.objectForKey("profilePicture") != nil {
let thumbnail = sender?.objectForKey("profilePicture") as? PFFile
thumbnail?.getDataInBackgroundWithBlock({
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
imageView.image = UIImage(data:imageData!)
} else {
println(error)
}
})
}
}
That's because you're not waiting until the images are finished loading when you update the UIImageView. Try Using this code:
var query = PFQuery(className:"Users")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
self.scored = objects!.count
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
let userImageFile = object["Image"] as! PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
self.imageArray.append(image!)
}
}
dispatch_async(dispatch_get_main_queue()) {
//don't reload image view here!
}
}
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
dispatch_async(dispatch_get_main_queue()) {
//wait until here to reload the image view
if self.imageArray.isEmpty == false {
//image array is not empty
self.ImageView.image = imageArray.first
}
else {
//no images found in parse
}
}
I am attempting to check if a PFFile has data before it attempts to pull the image from the background. I am attempting this because I keep getting a fatal crash if you try and open one of the objects and there is no image! My problem is that I can't get the data check to work. PFFile != nil does not work and you can't check if it exists with if (recipeImageData) because PFFile does not conform to the boolean protocol. Any help would be appreciated!
Here is the declaration of the variable:
var recipeImageData: PFFile = PFFile()
And here is the function for fetching the data:
override func viewWillAppear(animated: Bool) {
navItem.title = recipeObject["Name"] as? String
recipeImageData = recipeObject["Image"] as PFFile //Fatally crashes on this line
// Fetch the image from the background
if (recipeImageData) {
recipeImageData.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
self.recipeImage.image = UIImage(data: imageData)?
} else {
println("Error: \(error.description)")
}
})
}
}
EDIT:
I just tried this seeing that I probably am making a check in the wrong area. Here is my updated code.
override func viewWillAppear(animated: Bool) {
navItem.title = recipeObject["Name"] as? String
if let recipeImageData = recipeObject["Image"] as? PFFile {
// Fetch the image in the background
recipeImageData.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
self.recipeImage.image = UIImage(data: imageData)?
} else {
println("Error: \(error.description)")
}
})
}
}
This check actually works just fine, there was another issue that was causing the crash. The correct code is posted below:
override func viewWillAppear(animated: Bool) {
navItem.title = recipeObject["Name"] as? String
if let recipeImageData = recipeObject["Image"] as? PFFile {
// Fetch the image in the background
recipeImageData.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
self.recipeImage.image = UIImage(data: imageData)?
} else {
println("Error: \(error.description)")
}
})
}
}