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

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

Related

RealmSwift. Difficulties initializing List after converting to Swift 4

I've got a task to convert an existing project to Swift4 (from Swift 2.3, don't ask O_o). Managed to fix almost everything except this issue using RealmSwift:
Old code:
class func myFunc() -> List<MyClass> {
let realm = try! Realm()
return List(realm.objects(MyClass).sorted("name", ascending: true))
}
Getting compiler error for the return statement:
Argument passed to call that takes no arguments
When I trying to fix like this, compiler is silent, but the function doesn't do its job:
return List<MyClass>()
So which is then the right way to initialize List with a collection of custom objects? Please, help!
List doesn't have an initializer accepting a Results instance in RealmSwift 3.1.0 (I'm not sure since when though). List's only initializer doesn't take any input arguments and it creates an empty List instance.
You can work around this by creating an empty List using the only initializer, then calling append to add the elements of the Results collection to the list.
func myFunc() -> List<MyClass> {
let realm = try! Realm()
let list = List<MyClass>()
list.append(objectsIn: realm.objects(MyClass.self).sorted(byKeyPath: "name", ascending: true))
return list
}

How to fetch core data objects into Dictionary in Swift?

I've saved objects in core data, and I am looking how to fetch those objects as a Dictionary
Here is an example of my code where sections is keys for the dictionary and Company as an array of core data objects.
private var companies = Dictionary<String, Array<Company>>()
private var sections: [String] = ["Pending", "Active", "Pending"]
override func viewWillAppear(_ animated: Bool) {
let fetchRequest : NSFetchRequest<Company> = Company.fetchRequest()
let moc = DatabaseController.getContext()
do {
let request = try moc.fetch(fetchRequest)
for case let (index, object) in request.enumerated() {
companies[sections[index]]!.append(object)
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}}
When I am trying to execute my code, I have an error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Could anyone help me with that issue?
That error message means that you're force unwrapping an optional that doesn't have a value. In other words you're using ! where you shouldn't. (You should basically never use the force unwrap operator (!).)
Let's look at the line where you do that:
companies[sections[index]]!.append(object)
If we break this down and add the inferred types we have:
let section: String? = sections[index]
let companyArray: Array<Company> = companies[section]!
You're crashing because companies starts off empty, so asking for any of the arrays will return nil. (Actually, I'm not sure how your code is compiling, since you can't subscript into the dictionary with an optional.)
However, if you fix that, we still have a problem because you're using the index of the fetched array to look up the section. If you have more than three companies, that will start to fail.
I suspect you want something like:
for let company in result {
if var companyArray = companies[company.status] {
companyArray.append(company)
} else {
companies[company.status] = [company]
}
}
Where status is an invented property on Company that returns a String like "Pending" or "Active".
I've found the solution, just need to use NSFetchResultController in order to display data in TableView by different sections.

Deleting object from parse-server code causing error?

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()
}

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)

Swift parse framework and closures

This is srsly driving me crazy.
I am trying to use getFirstObjectInBackgroundWithBlock() method in swift but I can't figure out how to (not) use the optionals ..
I just want to get the user's score from the parse server And I do it like this:
func updateScoreForCurrentUser(score: Int){
let user = PFUser.currentUser()
// get gameScore for user
var query = PFQuery(className: "GameScore")
query.whereKey("User", equalTo: user!)
query.getFirstObjectInBackgroundWithBlock { (gameScore: PFObject, error: NSError?) -> Void in
gameScore["score"] = score
}
I just get a "Cannot invoke 'getFirstObjectInBackgroundWithBlock' with an argument list of type '((PFObject?, NSError?) -> Void)'"
Can you pleaase help me? Thank you
This error that you are getting is, as you've guessed already that you need to hvae gameScore object as an optional.
"Cannot invoke 'getFirstObjectInBackgroundWithBlock' with an argument
list of type '((PFObject?, NSError?) -> Void)'"
This is not because of swift or its limitations. It's because Parse SDK defines that function like that. And unless Parse changes its API, you will have to use an optional.
And just my two cents on the matter, an Optional is in order here.
Either you will get a PFObject or you will get an Error, not both. So one of them will be nil, hence the use of Optional.