Parse findObjectsInBackgroundWithBlock error part not working - ios

in my parse table there are columns. location and country. and if it is true data will load to the application.but the problem is, its never going to else part in
findObjectsInBackgroundWithBlock even wherekeys wrong. always print out This section calling line.
var findLiveFeedData:PFQuery = PFQuery(className: "Spreads")
findLiveFeedData.whereKey("location", equalTo: city)
findLiveFeedData.whereKey("country", equalTo: country)
findLiveFeedData.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?, error:NSError?)->Void in
if error == nil{
if let objects = objects as? [PFObject] {
for object in objects{
self.LiveFeedData.addObject(object)
}
}
println("This section calling")
let array:NSArray = self.LiveFeedData.reverseObjectEnumerator().allObjects
self.LiveFeedData = NSMutableArray(array: array)
self.tableView.reloadData()
}else{
println("Error") // This section never gets called
}
}

Even if you make a query with the wrong key it won't return an error, it will return an array with 0 entries. So the way to find out if nothing has been found it to use:
if objects != nil {
if objects!.count > 0 {
//You are safe to use the array
} else {
//Nothing was returned
}
}

Related

Append UI Images from array to slideshow swift

I'm trying to make a slideshow with this library
https://github.com/zvonicek/ImageSlideshow
So i'm making a query, i bring some images and i append them here
var sliderArray = [UIImage]()
var testimg:UIImage!
let idaki = recipeObj.objectId
let pointer2 = PFObject(outDataWithClassName:"Recipes", objectId: idaki!)
let galquery = PFQuery(className:"sliderRecipes")
galquery.whereKey("recipe", equalTo: pointer2)
galquery.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects {
for object in objects {
count += 1
let glrimg = object["sliderImage"] as! PFFile
glrimg.getDataInBackgroundWithBlock {
(imageData3: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData2 = imageData3 {
self.testimg = UIImage(data:imageData2)
print(self.testimg)
print(self.sliderArray)
self.sliderArray.append(UIImage(data:imageData2)!)
}
if count == objects.count { print(self.sliderArray) }
}
}
// print("test")
// print(self.sliderPinakas)
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
And after all this i DONT have an array with images. In the print above it first shows the empty array and after that it shows the prints of UI Images that i want to show them like this to a slider
slideshow.setImageInputs([ImageSource(image: UIImage(named: "myImage"))!, ImageSource(image: UIImage(named: "myImage2"))!])
but instead of having to do it with the name, UIImage(named: "myImage"))! i would like to do it this way
self.slider.setImageInputs([ImageSource(image: self.testimg)])
for all the images of the array, cause the above line shows only one.
Is there anyone that could help?
Thanks!
You have pass to self.slider.setImageInputs array of all objects ImageSource [ImageSource(image: self.testimg1), ImageSource(image: self.testimg2), ...] etc., not only one object [ImageSource(image: self.testimg)].
If you add images like:
self.slider.setImageInputs([ImageSource(image: self.testimg)])
self.slider.setImageInputs([ImageSource(image: self.testimg2)])
you'll simply replace first image with second.
Create new array, enumerate all images from sliderArray, and append they to array ImageSource(image: self.testimg1) objects.
Also remember, you have to call this from block glrimg.getDataInBackgroundWithBlock!
add before for
var count = 0
and add inside block
count +=1
if count == objects.count {
print(self.sliderArray)
}.
That will print array when all objects finished loads (they can loads in chaotic order).

For loop not being called in query function

I am calling the following function in the viewDidLoad of my collection view controller. I am trying to retrieve a value from the User class of my parse server. My problem is that the for loop is not being called which is not allowing the string value to be retrieved from the column and stored in the array.
func loaduuid(){
let query = PFQuery(className: "_User")
query.whereKey("uuid", equalTo: guestname.last!)
query.findObjectsInBackgroundWithBlock ({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
print("no error")
for object in objects!{
// add found data to arrays
self.newuuid.append(object.valueForKey("uuid") as! String)
print("uuid added")
}
}
else {
print(error?.localizedDescription)
}
})
}
Why is my for loop not being called and how can I fix this?
You should try to print(objects!.count) to see if the array of PFObjects is empty, that might be why is not iterating through the array. If it prints 0, it means that your query is not finding any results on the server.
If the user is logged in you have every information of his row from _User class in local device, you can access it with
let uuid = PFUser.currentUser()!["uuid"] as! String
or if there are some updated values in _User row you can use
PFUser.currentUser()?.fetchInBackgroundWithBlock...

how to properly check for an existing object in parse with swift

I've made a function that creates a "favorite" object back in parse with the tap of a favorite button on the UI :
//MARK: Create the favorite object
func createFavorite(){
let currentUser = PFUser.currentUser()
let currentBook = PFObject(withoutDataWithClassName: "Books", objectId: objectIdSelected)
let favorite = PFObject(className:"Favorites")
favorite["user"] = currentUser
favorite["books"] = currentBook
favorite.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// success
} else {
// There was a problem, check error.description
}
}
}
Now I am attempting to create a query that checks to see if a favorite object with those exact properties exists using the following logic, I've placed it in the viewDidLoad of a VC that shows a specific book:
//MARK: Check if there is a favorite object available
func isFavoritedByUser(){
let currentUser = PFUser.currentUser()
let currentBook = PFObject(withoutDataWithClassName: "Books", objectId: objectIdSelected)
let query = PFQuery(className:"Favorites")
query.whereKey("user", equalTo: currentUser!)
query.whereKey("books", equalTo: currentBook)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if objects != nil {
print("this book was favorited by this user")
} else if objects == nil {
print("this book WAS NOT favorited by this user")
} else if error == nil {
// succeed
} else if error != nil {
// There was a problem, check error.description
}
}
}
However, even if no favorite object with those properties exists back in my parse class, it still prints "this book was favorited by this user".. what am i missing here?
The list existing is not proof. That simply proves that some kinda of error weren't observed.
You should check that there was no error first, then you should check that the list of objects has one item in it.
If the list has more than one item then you're creating duplicates and you should fix that...
What you're getting returned is an array, as long as there isn't an error. So, rather than checking for nil, you should be checking the content of the returned array (objects) to see if there is anything in there.
In Parse's guide, you can see what they recommend for this function call:
https://parse.com/docs/ios/guide#queries
Additionally, Parse recommends considering getFirstObjectInBackground instead if this query only ever needs to return a single object, so that might be something to consider as an alternative.
So the problem was i was checking to see if object was nil rather then checking for the count, here is the correct code:
//MARK: Check if there is a favorite object available
func isFavoritedByUser(){
let currentUser = PFUser.currentUser()
let currentBook = PFObject(withoutDataWithClassName: "Books", objectId: objectIdSelected)
let query = PFQuery(className:"Favorites")
query.whereKey("user", equalTo: currentUser!)
query.whereKey("books", equalTo: currentBook)
query.findObjectsInBackgroundWithBlock { (object, error) -> Void in
if error == nil {
if object?.count > 0{
print("this book was favorited by this user")
} else {
print("this book WAS NOT favorited by this user")
}
} else {
}
}
}
For iOS, you can just check the dictionary on an object like so:
rideParse["driver"] == nil
If it exists, then you will get the pointer. If it doesn't/you did not query to include the pointer, then it will just return nil.

Iterate through a custom Parse column in Swift app

I want to know how I could store the entire custom column (the user Pointer<_User> column from a custom class) and put them all in an array variable so that I can see if a the user exists in that class or not. This is what I have:
Old Code
var objectUserIdArray = [String]()
let objectUserIdQuery : PFQuery = PFQuery(className: "Scores")
objectUserIdQuery.findObjectsInBackgroundWithBlock {
(objects : [PFObject]? , error : NSError?) -> Void in
var objectID = objects! as [PFObject]
for i in 0..<objectID.count {
objectUserIdArray.append(objectID[i].objectId!)
}
for _ in objectID {
print(objectUserIdArray)
}
New Code
func saveScoresOnParse() {
objectUserIdQuery.whereKey("User", equalTo: PFObject(withoutDataWithClassName: "_User", objectId: userID))
objectUserIdQuery.findObjectsInBackgroundWithBlock {
(objects : [PFObject]? , error : NSError?) -> Void in
if error == nil {
//var objectID = objects! as [PFObject]
/*for i in 0..<objectID.count {
self.objectUserIdArray.append( objectID[i].objectId! )
}*/
for _ in objects! {
print(objects)
}
// The score key has been incremented
for (var i = 0 ; i < self.objectUserIdArray.count ; i++) {
if self.userID != objects![i] {
print("New Scores")
print("R: \(self.rightAnswers)")
print("W: \(self.wrongAnswers)")
print("S: \(self.skippedQuestions)")
self.scores["User"] = PFUser.currentUser()
self.scores["Right"] = self.rightAnswers
self.scores["Wrong"] = self.wrongAnswers
self.scores["Skipped"] = self.skippedQuestions
self.scores.saveInBackground()
} else if self.userID == objects![i] {
print("Updated Scores")
self.scores.incrementKey("Right", byAmount: 1)
self.scores.incrementKey("Wrong", byAmount: 1)
self.scores.incrementKey("Skipped", byAmount: 1)
print("R: \(self.rightAnswers)")
print("W: \(self.wrongAnswers)")
print("S: \(self.skippedQuestions)")
self.scores.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// The score key has been incremented
} else {
// There was a problem, check error.description
}
}
} else {
print("Error")
}
}
} else {
print(error)
}
}
But it only stores the objectId column and not the Pointer<_User> column. I know this because when I print the stuff that is inside, it prints out the objectIds.
This is what happens, instead of just updating the current user's scores, it just makes new ones. I want the if statement to check if the user already exists in that column and if it does updates the scores and if it doesn't, make new ones. (The new code's if statement doesn't work, i have to bring it out for it to save...)
Your updated question make clearer what you are actually wanting to do;
Save or update a user's scores in your Parse Score object. To do this, there is no reason to retrieve any object Ids or loop through any results. More often than not you don't do use Object Ids explicitly when using Parse; you can simply pass the object itself with Parse working out the references for you.
I am not sure how you exactly want to change the scores; in your code above you increment in one case but set the scores explicitly in another, but the code below shows the general approach.
If you are frequently or repeatedly going to update a score record then you could make your code more efficient by holding a reference to the Scores object in a property after you find it the first time and simply update & save it subsequently.
func saveScoresOnParse() {
if let currentUser=PFUser.currentUser() {
let scoreQuery= PFQuery(className: "Scores")
scoreQuery.whereKey("User",equalTo:currentUser)
scoreQuery.getFirstObjectInBackgroundWithBlock {
(object : PFObject? , error : NSError?) -> Void in
if error == nil {
var scoreObject=object ?? PFObject.objectWithClassName("Scores")
if (scoreObject["User"]==nil) {
scoreObject["User"]=currentUser
}
scoreObject["Right"]=self.rightAnswers
scoreObject.saveInBackground()
} else {
print(error)
}
}
} else {
print("No current user!")
}
}

Swift Parse - local datastore and displaying objects in a tableview

I am building and app that saves an object in the local datastore with parse. I then run a query to retrieve the objects that are in the local datastore and it is working fine. however, I would like to grab the object, and the contents in it, and set some labels in a table view cell based on the items that are stored in the parse local data store object. for example, i make an object with attributes like "objectID", "name", "date", "location". what i'd like to do is to have a table view on the home screen that displays the name, date, location ...etc. of each item that was saved in local datastore in labels in each cell.
i know that im saving it correctly:
// parse location object
let parseLighthouse = PFObject(className: "ParseLighthouse")
parseLighthouse.setObject(PFUser.currentUser()!, forKey: "User")
parseLighthouse["Name"] = self.placeTitle.text
parseLighthouse["Note"] = self.placeNote.text
parseLighthouse["Locality"] = self.placeDisplay.text!
parseLighthouse["Latt"] = self.map.region.center.latitude
parseLighthouse["Longi"] = self.map.region.center.longitude
parseLighthouse["LattDelta"] = 0.5
parseLighthouse["LongiDelta"] = 0.5
parseLighthouse["Date"] = dateInFormat
parseLighthouse.pinInBackground()
parseLighthouse.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
println("Object has been saved. ID = \(parseLighthouse.objectId)")
}
and when i run the query, im able to access the attributes by running println(object.objectForKey("Name"))
func performQuery() {
let query = PFQuery(className: "ParseLighthouse")
query.fromLocalDatastore()
query.whereKey("User", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) lighthouses.")
// Do something with the found objects
if let light = objects as? [PFObject] {
for object in light {
println(object.objectId)
println(object.objectForKey("Name"))
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
because when running the query, i get back the object id and name as expected.
Successfully retrieved 2 lighthouses.
Optional("A3OROVAMIj")
Optional(happy)
Optional("bbyqPZDg8W")
Optional(date test)
what I would like to do is grab the name field within the parse object local data store, and that be the name of the label on a cell in a table view controller.
i dont know how to access that info from the object, and set the label correctly.
does anyone know how this is possible?
It's always a good idea to avoid pointer lol ... so why not saving the userid or username with the specific object..
so change this line:
parseLighthouse.setObject(PFUser.currentUser()!, forKey: "User")
TO
parseLighthouse["username"] = PFUser.currentUser().username
Answer
NOW let's create a struct that contains the objectID and the Name outside of your Controller Class.
struct Data
{
var Name:String!
var id:String!
}
then inside of the Controller class, declare the following line of code globally
var ArrayToPopulateCells = [Data]()
Then your query function will look like :
func performQuery() {
let query = PFQuery(className: "ParseLighthouse")
query.fromLocalDatastore()
query.whereKey("User", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(objects!.count) lighthouses.")
// Do something with the found objects
if let light = objects as? [PFObject] {
for object in light {
print(object.objectId)
print(object.objectForKey("Name"))
var singleData = Data()
singleData.id = object.objectId
singleData.Name = object["Name"] as! String
self.ArrayToPopulateCells.append(singleData)
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
}
In the tableView numberOfRowinSection()
return ArrayToPopulateCells.count
In the cellForRowAtIndexPath()
var data = ArrayToPopulateCells[indexPath.row]
cell.textlabel.text = data.objectID
cell.detailLabel.text = data.Name
VOila that should be it

Resources