Parse:Swift: getDataInBackground, but data doesn't exist - ios

I have a problem with parse. I was trying to save profile pics for my users, which worked perfectly. Then I wanted to show the profile pic inside an image view, if the user looks at his own profile. Problem is that when a user hasn't set an profile pic before, it lets my app crash, because there is no data to find when it tries to do the getDataInBackgroundWithBlock function. How can I solve this? Here is my code that should display the corresponding profile pic inside the profilePicImageView. I tried it without the else statement before, same problem :/
let profileImage = currentUser?.objectForKey("profilePic") as? PFFile
profileImage!.getDataInBackgroundWithBlock({ (imageData:NSData?, error:NSError?) -> Void in
if (error == nil){
let image:UIImage = UIImage(data: imageData!)!
self.profilePicImageView.image = image
}else {
self.profilePicImageView.image = nil
}
})

ParseUI has a class named PFImageView, which is a subclass of UIImageView. Instead of using UIImageView, you can do something like:
1. Set the class to PFImageView in Interface Builder
2. Make an outlet to that PFImageView to profilePicImageView
3. Change your code to:
self.profilePicImageView,image = <Any placeholder>
if let profileImage = currentUser?.objectForKey("profilePic") as? PFFile {
self.profilePicImageView.file = profileImage
self.profilePicImageView.loadInBackground()
}

Related

Parse array images saving and fetching

I have a mosaic app that takes multiple size photos and breaks them into smaller photos. Depending on the size of the photo, the amount of smaller photos could vary. Now I have an NSMutableArray named imageNameList2 that holds all of the smaller images taken from the larger image. For this example I showed an example with the images being called from the image assets list to make it easier to answer this question.
Here is the imageNameList (NSMutableArray that holds all the smaller images)
var imageNameList: [String] {
var imageNameList2:[String] = [] //[NSMutableArray]()
for i in 0...149 {
let imageName = String(format: "pic_%03d", Int(i))
imageNameList2.append(imageName)
}
return imageNameList2
}
What I'd like to do is have a continue button that will save all these images in order as piffles or any other format to parse that works best and have another button called retrieve that will retrieve all these photos from parse. I basically have a parse server that utilizes parse frameworks to help speed up the backend process. Can you please show me how I would save and retrieve this NSMutableArray if there are different numbers of stored images each time?
I think you're trying to do something like this. This is just an example. There's a lot of work to be done but hopefully this will get you started. I did not run or test this code.
The idea is to save your images as PFFiles, and create a 'tile' PFObject for each file. Then save all the 'tile' PFObjects to a 'tiles' key of the image PFObject. Then recall the image when you need it by objectId.
Good luck.
let appleTiles = ["apple1, apple2, apple3"]
let orangeTiles = ["orange1, orange2, orange3, orange4, orange5"]
func usage() {
//dont literally run these synchronously like this
post(appleTiles)
post(orangeTiles)
download()
}
func post(_ tileNames: [String]) {
let image = PFObject(className: "Image")
let tilesPF = tileNames.map({ name in
let data = UIImagePNGRepresentation(UIImage(named: name))!
let file = PFFile(data: data)
let tile = PFObject(className: "Tile")
tile["tile"] = file
})
image["tiles"] = tilesPF
image?.saveInBackground(block: { responseObject, error in
//you'll want to save the object ID of the PFObject if you want to retrieve a specific image later
})
}
func download() {
let query = PFQuery(className: "image")
//add this if you have a specific image you want to get
query.whereKey("objectId", equalTo: "someObjectId")
query.findObjectsInBackground({ result, error in
//this is probably close to how you'd unwrap everything but again, I didn't test it so...
if let objects = result as? [PFObject], let first = objects.first, let image = first["image"] as? PFObject, let tiles = image["tiles"] as? [PFObject] {
tiles.forEach({ tile in
let file = tile["tile"]
//now you have an individual PFFile for a tile, do something with it
})
}
})
}

Adding image from Firebase to UITableViewCell

I want to retrieve the image that is stored in the storage of an user and place it next to his name in a custom UITableViewCell. The problem now is that the tableview will load when the images aren't done downloading (I think?), causing the application to crash because the image array is nil. So what is the correct way to load the tableview? I think, for the user experience, it is important that the tableviewcell image should be shown even if the images aren't done downloading, and present them a default image that is saved in the assists. I thought about making an array with UIImages that links to the default asset of loading an image and changing the image to the profile picture when it is done downloading. But I really have no clue how to do that. This is what I got so far about downloading the image:
let storage = FIRStorage.storage()
let storageRef = storage.reference(forURL: "link.appspot.com")
channelRef?.observeSingleEvent(of: .value, with: { (snapshot) in
if let snapDict = snapshot.value as? [String:AnyObject]{
for each in snapDict{
let UIDs = each.value["userID"] as? String
if let allUIDS = UIDs{
let profilePicRef = storageRef.child((allUIDS)+"/profile_picture.png")
profilePicRef.data(withMaxSize: 1 * 500 * 500) { data, error in
if let error = error {
}
if (data != nil)
{
self.playerImages.append(UIImage (data: data!)!)
}
}
}
let userNames = each.value["username"] as? String
if let users = userNames{
self.players.append(users)
}
}
}
self.tableView.reloadData()
})
This is in the cellForRow
cell.playersImage.image = playerImages[indexPath.row] as UIImage
My rules, haven't changed it from the default rules:
service firebase.storage {
match /b/omega-towers-f5beb.appspot.com/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
Thank you.
Regarding user experience, you are correct. It is standard to have some sort of default image when loading an image from a URL. A great library to use for image caching and using default assets in its' place is AlamofireImage
Vandan Patel's answer is correct in saying you need to ensure your array is not nil when loading the tableview. You will be given a completion block to handle any extra work you would like to do with your image, using the AlamofireImage library.
This is all assuming you are getting a correct image URL back for your Firebase users.
You should call tableView.reloadData() when the images are done downloading. One important thing, initialize your playerImages as playerImages = [UIImage]() instead of playerImages: [UIImage]!. if it's empty, it wouldn't show your array is nil.
Update:
if let players = playerImages {
//code
}

Retrieving an image to my UIImageView

I load the image using my Android application Parse in my database, and I want to show it on my iphone.
when I run the Xcode tells me: 'Could not release the value of type' NSConcreteData 'to' PFFile ''
there any way to get this image and show on my iPhone (UIImageView) ??
Any idea to help me ?
I'll be very grateful !!
enter image description here
The problem is, as the Compiler tells you, that you're trying to cast NSData to PFFile.
Just use:
let userImageProfilePicture = event["profile_picture"]
userImageProfilePicture.getDataInBackgroundWithBlock({ (data, error) -> Void in
// handle here with your userAuth == true block
if let data = data where error == nil{
var image = UIImage(data: data)
}
})

Issue converting NSData to UIImage via Parse.com download

I'm having a strange issue. My app works fine in the iPhone 6 emulator, but not in any other emulators or on my iDevice. Here's the main code
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if(error == nil){
let imageObjects = objects as! [PFObject]
if let myObjects = objects {
for object in myObjects {
let myTitle = object["imageName"] as! NSString
println(myTitle)
let thumbNail = object["imageFile"] as! PFFile
// println(thumbNail)
thumbNail.getDataInBackgroundWithBlock({
(imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
self.imageArray.append(imageData!)
let image = UIImage(data:imageData!)
self.imageView.contentMode = .ScaleAspectFit
self.imageView.image=image
}
})//getDataInBackgroundWithBlock - end
}//for - end
}
}//end of if
else{
println("Error in retrieving \(error)")
}
}//findObjectsInBackgroundWithblock - end
I think this line is the culprit
let image = UIImage(data:imageData!)
But I'm not sure why. "image" returns nil in all other devices except iPhone 6 emulator. Any suggestions would be awesome.
Thanks
NOTE: the image displays just fine in iPhone 6 emulator. I'm using storyboard and unchecked autolayout.
There shouldn't really be a situation where the app only works on one simulator setting. Resetting your simulator should solve the problem.
One possibility is that you previously successfully downloaded this data, and Parse has cached the response in your iPhone app, but you've since changed the PFObject remotely and removed the image data. Or perhaps changed code.
Because Parse.com caches images, it's possible that it works only on this device because of Parse.com caching.
You could use the debugger, or worse, NSLog to determine what is nil. You need to determine if imageData is coming back nil or not. Also, is there a reason why you're assuming imageData is non-null? I'm referring to references to imageData! -- that seems dangerous. Just because there's no error doesn't mean imageData is non-null.

Display random image with ImageView

I finally was able to pull an array of images from Parse.com after fiddling with tutorials.
From that array I want to throw it on an image view via next random image with a swipe gesture:
var query = PFQuery(className:"cats")
query.findObjectsInBackgroundWithBlock {(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
for object in objects! {
// Update - replaced as with as!
self.imageFiles.append(object as! PFObject)
println(self.imageFiles)
self.view.addGestureRecognizer(rightSwipe)
}
} else {
// Log details of the failure
println(error)
}
}
}
The println(self.imageFiles) actually shows the array of files which is great, what I'm having issues with is using the random generator.
Still new to syntax, I was trying to do like imageview.image = imageFiles[0] or something like that to just display one of the images in the array. Not really sure the syntax though.
I'm guessing once I get that it would be imageview.image = imageFiles[RandomNumber] or the equivalent.
for the swipe part I think I got that under control
Edit
ok I have:
let randomNumber = imageFiles[Int(arc4random_uniform(UInt32(imageFiles.count)))]
println(randomNumber)
and the println gives me a random image file from the array.
How do I put that into the image view?
EDIT
just tried:
for randomNumber in imageFiles {
self.ImageView.image = randomNumber
}
and got:
cannot assign a value type pfobject to a value type of uiimage
self.ImageView.image = UIImage(data: randomNumber)
also gives me an error can't have data: PFObject

Resources