Swift 3 upload image to Parse Server - ios

I'm trying to upload an image to Parse Server usinf PFFile. I'm not having issues uploading it manually from Parse Dashboard and retrieving it from the app. But if I try to upload a new one with this method, the image is not being updated.
The rest of fields are beeing uploaded correctly (name, lastname, username and email)
Save method:
#IBAction func saveBtnPressed(_ sender: Any) {
print("Start saving...")
let imageData = UIImagePNGRepresentation(profilePic.image!)
print ("imageData value:")
print(imageData!)
let imageFile = PFFile(name:"avatar.png", data:imageData!)
print ("imageFile value:")
print(imageFile!)
let query = PFQuery(className: "_User")
query.whereKey("username", equalTo: (PFUser.current()?.username)!)
query.findObjectsInBackground(block: { (objects, error) in
if let user = objects {
for object in user {
object["name"] = self.nameFld.text
object["lastname"] = self.lastnameFld.text
object["username"] = self.emailFld.text
object["email"] = self.emailFld.text
object["avatar"] = imageFile
print(object)
object.saveInBackground()
}
}
})
}
Output:
Start saving...
imageData value:
8358983 bytes
(lldb)

To make this work you will need to upload picture only first and then reference it to the user
let imageData = UIImagePNGRepresentation(profilePic.image!)
print ("imageData value:")
print(imageData!)
let imageFile = PFFile(name:"avatar.png", data:imageData!)
print ("imageFile value:")
print(imageFile!)
imageFile.saveInBackground { (result, error) in
if let error = error{
print(error)
}else{
let query = PFQuery(className: "_User")
query.whereKey("username", equalTo (PFUser.current()?.username)!)
query.findObjectsInBackground(block: { (objects, error) in
if let user = objects {
for object in user {
object["name"] = self.nameFld.text
object["lastname"] = self.lastnameFld.text
object["username"] = self.emailFld.text
object["email"] = self.emailFld.text
object["avatar"] = imageFile
print(object)
object.saveInBackground()
}
}
})
}
}
}
Be aware that in the above example the file is always uploaded to the server even if no users match the query so consider uploading file only after getting query results.

There is no need to query current user. You can do it as follows:
#IBAction func saveBtnPressed(_ sender: AnyObject) {
let userToUpdate = PFUser.current()!
userToUpdate["name"] = self.nameFld.text
userToUpdate["email"] = self.emailFld.text
userToUpdate["username"] = self.emailFld.text
// Save Avatar
if profilePic.image != nil {
let imageData = UIImageJPEGRepresentation(profilePic.image!, 0.5)
let imageFile = PFFile(name:"avatar.jpg", data:imageData!)
userToUpdate["avatar"] = imageFile
}
// Saving block
userToUpdate.saveInBackground(block: { (succ, error) in
if error == nil {
print("Your Profile has been updated!")
} else {
print("Failed")
}})
}

Related

When talking to Parse server (using Swift on iOS), why PFFileObject keeps returning nil?

Why does PFFileObject keeps giving me an error like Foundation._GenericObjCError.nilError and if I use PFFileObject(name:data:) to create a file object, I will get nil.
My code looks like:
func uploadImageFileToParseServer(image: UIImage, uid: String) {
guard let imageData = image.pngData() else {
UILogger.error("Null imageData")
return
}
UILogger.log("creating imageFile using \(uid) and \(imageData) under name \(uid)-img.png")
let unwrappedImageFile = try? PFFileObject(name: "\(uid)-img.png", data: imageData, contentType: "image/png")
unwrappedImageFile?.saveInBackground { (result, error) in
if let error = error{
UILogger.error("\(String(describing: error))")
} else {
let query = PFQuery(className: "User")
UILogger.log("Saving to User with uid \(uid)")
query.whereKey("objectId", equalTo: uid)
query.findObjectsInBackground(block: { (objects, error) in
if let user = objects {
for object in user {
UILogger.log("User \(uid) found. Updating his/her avatar column now")
object["avatar"] = unwrappedImageFile
object.saveInBackground { isSuccessful, error in
if !isSuccessful {
UILogger.error("Error in updating User - \(error.debugDescription)")
}
}
}
}
})
}
}
}

How to block users in my app (swift + parse)

I am building an app using parse where users can click in annotation in a map and see a picture of that place.
My problem is with the block button ... It does not work, when the user click on the block button, he should not see any annotation by the user he is blocking but that unfortunately does not work .
Here is my block button :
#IBAction func blocking(_ sender: Any) {
let block = PFObject(className: "blocking")
block["me"] = PFUser.current()?.username
block["poster"] = post?.name
block["posterID"] = post?.id
block.saveInBackground { (succ, error) in
if error != nil {
print("rttot")
} else {
self.performSegue(withIdentifier: "mo", sender: nil)
}
}
}
(note the poster ID is the ID of person who post the the picture and poster is the name of the person who made the post)
This action will start a relationship between the the user and the user who is blocking . now I will not show any post that hold the person I am blocking ID .
let queryy = PFQuery(className: "blocking")
queryy.whereKey("me", equalTo: PFUser.current()?.username)
queryy.findObjectsInBackground { (objects, error) in
if error != nil {
print("error")
} else {
for object in objects! {
if let neww = object.object(forKey: "posterID") {
var query = PFQuery(className: "posts")
query.whereKey("id", notEqualTo: neww)
query.findObjectsInBackground { (objects, error) in
if error != nil {
print("error")
} else {
for object in objects! {
let post = Posts()
post.chosen = object.object(forKey: "chosen") as! String
post.lati = object.object(forKey: "lati") as! Double
post.longi = object.object(forKey: "longi") as! Double
post.image = object.object(forKey: "image") as? PFFile
post.text = object.object(forKey: "text") as! String
post.name = object.object(forKey: "name") as! String
post.uid = object.object(forKey: "uid") as! String
post.id = object.object(forKey: "id") as! String
print("999")
var cord = CLLocationCoordinate2D(latitude: post.lati, longitude: post.longi)
let anno = annoClass(cord: cord, post: post, text: "Destination", subText: "ClickMe")
self.myMap.addAnnotation(anno)
}
}
}
}
}
}
}
As you can see it will take the ID of people I am blocking and not showing their posts in the map but that does not work . The app does not show any error or bug btw.
Try This
queryy.whereKey("User_has_Blooked", equalTo: false) // if its equal to true, it should not show the users. make this object in the same class when you fetch users in the map!

Add multiple query results to array

I am trying to run 4 queries from my parse database, each pulling just 1 object. I am trying to add each of the objects to an array that can then be used in a collection view. The queries run successfully but the app crashes because it is pulling null values. Here is my code:
var query1desc = ""
var query2desc = ""
var descs = [String]()
fileprivate func fetchUsers() {
let query1 = PFQuery(className: "Messages")
query1.limit = 1
query1.findObjectsInBackground{
(objects, error) -> Void in
if error == nil {
if objects?.count == 0 {
} else {
let object = objects![0] as! PFObject
self.query1desc = object["message"] as! String
}
}
}
let query2 = PFQuery(className: "Messages")
query2.limit = 1
query2.findObjectsInBackground{
(objects, error) -> Void in
if error == nil {
if objects?.count == 0 {
} else {
let object = objects![0] as! PFObject
self.query2desc = object["message"] as! String
}
}
}
self.descs = [self.query1desc, self.query2desc]
self.collectionView.reloadData()
Does anyone know of a way to fix this so that self.descs does not just provide nil values? When I print within the query itself I know that objects are being pulled. Thanks in advance.
I think desc variable holds nil value because your program is executing an array assignment code part while completion handlers are still processing query requests. You need to wait until all your query requests finish and then can collect all the results.
let workGroup = DispatchGroup()
let queueForQuery1 = DispatchQueue(label: "firstQuery")
let query1 = PFQuery(className: "Messages")
query1.limit = 1
workGroup.enter()
queueForQuery1.async(group:workGroup) {
query1.findObjectsInBackground{ (objects, error) -> Void in
if error == nil {
if objects?.count == 0 {
} else {
let object = objects![0] as! PFObject
self.query1desc = object["message"] as! String
}
}
workGroup.leave()
}
}
let queueForQuery2 = DispatchQueue(label: "secondQuery")
let query2 = PFQuery(className: "Messages")
query2.limit = 1
workGroup.enter()
queueForQuery2.async(group:workGroup) {
query2.findObjectsInBackground{ (objects, error) -> Void in
if error == nil {
if objects?.count == 0 {
} else {
let object = objects![0] as! PFObject
self.query1desc = object["message"] as! String
}
}
workGroup.leave()
}
}
workGroup.notify(queue: DispatchQueue.main){
self.descs = [self.query1desc, self.query2desc]
self.collectionView.reloadData()
}

Swift 2. using Parse I can't save results of a PFUser.query() in an username array

Well I'm trying to save the results of a query and when I try to save it in an array it just doesn't do it.
Here's my code:
let query = PFUser.query()
query?.orderByDescending("puntaje")
query?.limit = 50
query?.findObjectsInBackgroundWithBlock({
(users, error) -> Void in
if let objects = users {
for object in objects {
self.usernames.removeAll(keepCapacity: true)
self.scores.removeAll(keepCapacity: true)
if let user = object as? PFUser {
print(user.username)
self.usernames.append(user.username!)
self.scores.append((user["puntaje"] as? Int)!)
}
}
}
print(self.usernames.count)
})
while printing user.username appears all the usernames.
and in the print it shows that I have 0 usernames.
You need to move
self.usernames.removeAll(keepCapacity: true)
self.scores.removeAll(keepCapacity: true)
above the "for" loop. Right under
if let objects = users {
I found another way.
I used:
let query = PFUser.query()
query?.orderByDescending("puntaje")
query?.limit = 50
do {
if let users = try query?.findObjects() {
for user in users as! [PFUser] {
let name = user.username!
self.usernames.append(name)
self.scores.append((user["puntaje"] as? Int)!)
}
}
}catch {
print(error)
}

How to save images to Parse?

For some odd reason, my images have stopped saving to parse. Before, my code worked fine and I have not made any changes to it at all.
Here is my code:
var posts = PFObject(className: "Product")
posts["shortDescription"] = productShortDescription
posts["user"] = PFUser.currentUser()
posts["longDescription"] = productLongDescription
posts["title"] = productTitle
posts["price"] = productPrice
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
//success saving, now save image
//create image data
var imageData = UIImagePNGRepresentation(self.newItemImageView.image)
//create parse file
var parseImageFile = PFFile(name: "upload_image.png", data: imageData)
posts["imagePNG"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
// take user home
println("data uploaded")
self.performSegueWithIdentifier("returnHomeAfterUpload", sender: self)
}else {
println(error)
}
})
}else {
println(error)
}
})
Everything else is stored perfectly, but what's the issue with my image data?
Thanks!
In your code you are not saving parseImageFile, so first parseImageFile.SaveInBackground and on success set it to posts and then save posts as well
Should be something like this
var posts = PFObject(className: "Product")
posts["shortDescription"] = productShortDescription
posts["user"] = PFUser.currentUser()
posts["longDescription"] = productLongDescription
posts["title"] = productTitle
posts["price"] = productPrice
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
//success saving, now save image
//create image data
var imageData = UIImagePNGRepresentation(self.newItemImageView.image)
//create parse file
var parseImageFile = PFFile(name: "upload_image.png", data: imageData)
parseImageFile.saveInBackgroundWithBlock({
posts["imagePNG"] = parseImageFile
posts.saveInBackgroundWithBlock({
(success: Bool, error: NSError?) -> Void in
if error == nil {
// take user home
println("data uploaded")
self.performSegueWithIdentifier("returnHomeAfterUpload", sender: self)
}else {
println(error)
}
})
})
}else {
println(error)
}
})
I haven't test this code on editor you may find some syntax error, but it should be something like this...
so things is when you create parseImageFile and then saveInBackground and inside block set it posts and then save post again
I've checked your code and it's works fine.
let image = UIImage(named: "img.jpg")
let data = UIImagePNGRepresentation(image)
let file = PFFile(name: "img", data: data)
let parseObj = PFObject(className: "testClass")
parseObj["text"] = "hello"
parseObj["image"] = file
parseObj.saveInBackgroundWithBlock { (_, _) -> Void in }
Try this, if this code will be works - easiest way for you is remove "Product" table and create it again.

Resources