Deleting object from parse-server code causing error? - swift

I am developing an app in Xcode using swift and am using a heroku-hosted parse-server as my database. I want to be able to delete an object from the database, but I keep getting an error when trying to type out the code. Here is what I have:
{
let removingObjectQuery = PFQuery(className: "GoingTo")
removingObjectQuery.whereKey("objectId", equalTo: goingToSelectionID)
removingObjectQuery.findObjectsInBackground(block: { (object, error) in
if let objects = object{
print("Object found")
for object in objects{
object.deleteInBackground()
}
}
})
}
But the delete .deleteInBackground keeps sending an error to in the code line saying that ".deleteInBackground is not a member of [PFObject]"... except that I thought it is a member of that value type?
Edit: Syntax fixed to allow calling of .deleteInBackground but now am receiving error in logs (which does not crash the app) that "[Error]: Object not found". The object is for sure in the DB and whereKey equalTo: is adequately described... (goingToSelectionID is indeed the objectId in the DB... checked this by printing to logs). Not sure what is wrong?

The findObjectsInBackground method doesn't return results of type PFObject, but [PFObject], which is an array of PFObjects... If you want to delete the whole array, you can use the class method deleteAllInBackground like so:
PFObject.deleteAllInBackground(objectt, block: nil)
Or you can iterate through the array:
for objectt in object! {
objectt.deleteInBackground()
}

Related

Unable to access variable outside of query function even though variable is declared after class

I have a few queries running to load variables with data from a Parse server into variables that are declared right below class. When I print the variable to the console within the query function, it prints correctly, but when I call it outside of the function or print it, it is empty. Any idea where I'm going wrong?
Variable declaration:
class AddTaskViewController: UIViewController, UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate {
var varCost = ""
Query loading variable:
let varCostQuery = PFQuery(className: "Class1")
varCostQuery.findObjectsInBackground(block: { (objects, error) in
if error != nil {
print(error!)
} else {
varCostQuery.whereKey("Header", equalTo: self.HeaderSelection.text)
varCostQuery.findObjectsInBackground(block: { (objects, error) in
for object in objects! {
self.varCost = object["pricePerUnit"] as! String
print(self.varCost) //Option1
}
})
}
})
print(varCost) //Option2
When I print Option1, I get the data exactly like I'm looking for, but when I print Option2 or try to do anything with the varCost variable at this level, I get "" like the variable has never been updated.
This occurs because the code being passed to the findObjectsInBackground method is code that is run only once all the objects have been found.
Because this code will only be called when the objects have been found, this may take a bit of time, so this code is send to a background queue to wait for the objects to be found.
We don't want the rest of our code to pause and wait for this though! That would slow our program down a lot. So the program continues past this block until it completes. That's why Option 2 is empty, because findObjectsInBackground hasn't had time to get the objects yet so the code has jumped straight to where Option 2 is.
When the objects have finally been found, the block of code is called and Option 1 is printed.
This means that you can only be sure self.varCost will have the right value from within this block (or closure, as it is called in Swift).

error: execution was interrupted, reason: breakpoint 1.2. Xcode 7.1, Swift

So the context is that I made a realm object and is giving one of it's variables a value, to do this I go ahead and call an instance of this object, then I connect to my server, get some value, then say something like
let someObject = someObjectClass() //this being a realm object class
someQuerySuccessBlock { (success, error) -> void in
...
if let someValue = objects[0].value {
someObject.id = someValue //this line is where the issue is
}
...
})
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction
realm.addObject(someObject)
realm.commitWriteTransaction
Error in llvm is error: execution was interrupted, reason: breakpoint 1.2.
Error does not show unless i make a breakpoint for all exceptions.
Also to note that code does compile, does run, will not cause a crash (but simply.. not run any of the code from that specific line onwards. That someObject does get saved and created, but the field that is to be assigned simply did not get assigned, etc
After some testing around, turns out this is because the realm object was already saved into Realm, where as the query block is async, it was trying to write into a variable of an object that had already been added.
Seems like the error was only like this because what I was trying to edit was the primaryKey of the object?
My fix:
let someObject = someObjectClass() //this being a realm object class
someQuerySuccessBlock { (success, error) -> void in
...
if let someValue = objects[0].value {
someObject.id = someValue //this line is where the issue is
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction
realm.addObject(someObject)
realm.commitWriteTransaction
}
...
})
If you try to edit the primary key of a saved object, then you will hit an assertion. Primary keys in Realm are immutable. Depending on your exact needs for your use case, you may want to create a new instance of your object class and assign all new properties which should be saved. You can add this new object then in a write transaction with -createOrUpdateInRealm:withValue:. Note: Be careful with to-one relations and other nullable properties as the merging strategy is here that null values are overwritten.

How to delete an entire [AnyObject] array retrieved with a `findObjectsInBackgroundWithBlock?

Does anyone know if its possible to delete an entire [AnyObject] array retrieved with a findObjectsInBackgroundWithBlock query?
The code bellow deletes one array item per time. But not all of them at once.
Have tried comments?.removeAll(keepCapacity: true) but compiler gives me an error: Immutable value of type '[AnyObject]' only has mutating members named remove all
getObjectInBackgroundWithId does not work as it only gets one object per time.
Quite stuck here... didn't find anything around about removing the whole array.
println("QUERY - DELETE COMMENTS")
var query = PFQuery(className: "Comments")
var post = currentObject
query.whereKey("bellongsToPost", equalTo: post)
query.findObjectsInBackgroundWithBlock { (comments: [AnyObject]?, error: NSError?) -> Void in
for comment in comments! as [AnyObject]
{
comment.deleteInBackground()
}
}
Just do:
PFObject.deleteAll(comments)
Obviously you need to unwrap comments, and do try catch if using Swift 2

Completion closure within a closure

Just starting to learn Swift coming from Obj-C - this is something simple I'm not understanding:
class func queryForAllUsersWithCallback(completion: (users :[User]?, error :NSError?) ->()) {
var query = PFQuery(className:User.parseClassName())
query.findObjectsInBackgroundWithBlock ({
(objects:[AnyObject]?, error: NSError?) in
completion(users: objects, error: error);
})
}
Give me a compiler error:
Cannot invoke 'findObjectsInBackgroundWithBlock' with an argument list of type '(([AnyObject]?, NSError?) -> _)'
If I comment out the line:
completion(users: objects, error: error);
the error goes away, so the warning is misleading.
completion takes as its first argument an array of User, whereas objects is an array of AnyObject. There’s no guarantee what is in objects is of the correct type (could be a motley collection of various types for all the compiler knows) so it won’t compile.
If you do a conditional cast it should compile, i.e.:
completion(users: objects as? [User], error: error)
Note, this will check at runtime that every element in objects really is of the correct type. If any of them aren’t, the whole array will be nil when passed to the completion handler. This will compile, since the argument is optional, but might be quite surprising/fail silently or even worse, crash because somewhere inside completion might be the assumption it isn’t nil, so it could get force-unwrapped.
So you might instead want to put some error handling in:
if let users = objects as? [User] {
completion(users: users, error: error)
}
else {
// log or fatalError or something
}
(apologies if the syntax of some of the above isn’t quite right, I haven’t tested the code since your snippet isn’t reproducible/stand-alone)
You just need to cast the objects to User as:
completion(users: objects as? [User], error: error)

By using swift, convert User's objectId as pointer to another class in synchronous by parse.com

In my Swift app, I am using parse.com for login. In USER class, "ObjectId" created for each and every registrations. Another class, contact form is there. That details saved in "contact_form". In the contact form, there is a object called "userId" which is pointer to USER class. That UserId data type is not in string. I don't know how to save objectId of User's class as Pointer in contact_form class. Kindly guide me. I don't want this parse code run as asynchronous. I want this to be run in synchronous. My Code is below.
//MY CODING
var query = PFQuery(className: "User")
query.whereKey("email", equalTo: PFUser.currentUser().email)
var obj_arr : NSArray = query.findObjects() //1 obj retrived
if let objects = obj_arr as? [PFObject] { // Synchronous
for object in objects {
var query_msg = PFQuery(className: "contact_form")
query_msg.whereKey("userId", equalTo: object.objectId) // Storing as String Error received. How to store as pointer.
}
}
Kindly guide me.
object.objectId is a String, but you want to match on a Pointer. Try changing
query_msg.whereKey("userId", equalTo: object.objectId)
to
query_msg.whereKey("userId", equalTo: object)