Error with Parse findObjectsInBackgroundWithBlock in Swift - arrays

I'm trying to retrive usernames from Parse's Server with findObjectsInBackgroundWithBlock. I want the results to be stored inside a NSArray, but I get an error in the code.
Here's it:
let query: PFQuery = PFUser.query()!
query.orderByAscending("username")
query.whereKey("username", notEqualTo: myUserId as! String)
query.findObjectsInBackgroundWithBlock {(objects:NSArray?, error:NSError?) -> Void in
}
And I'm getting this error:
Cannot convert value of type '(NSArray?, NSError?) -> Void' to expected argument type 'PFQueryArrayResultBlock?'
I know that everything is working when changing 'NSArray?' to '[PFObject]?', but I want to result to be an Array.. How can I solve this?

You need to do the following:
declare this:
var array:NSArray = NSArray()
query.findObjectsInBackgroundWithBlock {(objects:PFObject?, error:NSError?) -> Void in
if error != nil {
print("error")
} else {
if let objects = objects{
for object in objects {
self.append(object)
}
}
}
}

You can't force the conversion in the callback parameters. Your callback needs to respect the type that will be supplied and then your code in the callback can mutate the supplied parameters and store them.

Related

Generic Parameter T could not be inferred with optional generic array

I have a method in my Model class that has signature below:
func parse<T: Codable>(data: Data) throws -> Array<T>?
When I call the method in another class, Facade, I get the
Generic Parameter T could not be inferred
Calling function as below
if let data = data {
do{
let parsedArray = try self.model.parse(data: data);
}
catch{
print(error)
}
gives me the compiler warning on the line where I call the parse function.
You need to explicitly declare the type of the variable you are setting or add another parameter to the parse method and pass the desired type:
let parsedArray: [YourType] = try model.parse(data: data)

Storing array from Parse into local array

When I try to store arrays from Parse into a local array I can only access it within the findObjectsInBackgroundWithBlock {...}. When I print it outside of that block, it shows []...
Code :
var qArray : [[Int]] = []
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Trivia")
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) in
if objects != nil {
if let objects = objects {
for object in objects {
self.qArray.append(object["mainPattern"] as! [Int])
}
print(self.qArray) // Prints a multi dimension array
}
}
if error != nil {
print(error)
}
}
print(self.qArray) // prints []
}
It's most likely because the array hasn't been populated yet because it's running in the background. You can try using dispatch_group to circumvent this issue.
I think you're misunderstanding what findInBackground means. It means the code after the callback continues to execute, so it calls query.findInBackground.... and then it continues with the next line, which is print(self.qArray). At some point later on, it hears back from the database and it executes all the code inside the Callback, which is when the array finally gets populated.

Populating an array using Parse queries (Swift)

I am trying to populate an array with a query from my parse database. When I try to print out the content of the array, I get an EXC_BAD_INSTRUCTION error. It doesn't seem like I'm properly appending new elements into my array, I'd appreciate any sort of tips
func loadSampleTasks() {
tasks = [Task]()
let query = PFQuery(className: "Task")
query.whereKey("TaskName", equalTo: "kenny")
query.findObjectsInBackgroundWithBlock() {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil && objects != nil {
self.parseResults(objects!)
print(self.tasks) // this prints out Kenny object as expected
}
}
print(tasks) // prints an empty array
}
func parseResults(objects: Array<PFObject>){
for object in objects { //looping through returned data
print("no error in Parse lookup")
let parseResult1 = Task(name: object["TaskName"] as! String)
parseResult1?.completed = object["Completed"] as! Bool
print("Parse result in object loop: \(parseResult1!.name)")
tasks.append(parseResult1!)
}
}
Any help much appreciated!
To what thefredelement said, "This is happening because you're getting your parse results in a closure, which means it may execute after the function itself has already returned." Before this happens, though, it won't work properly and you'll come back with that error.
I got it to work. I had to tableView.reloadData() within the closure. Thank you so much for the help!

Parse: Download array in swift

I'm trying to search for data that contains a certain string then download an array from that row. I know how to do this in objective-c but not in swift. Here's the code I have to search for it:
let query = PFQuery(className:"Wait")
query.whereKey("latitude", equalTo:self.latitude)
query.findObjectsInBackgroundWithBlock {
(objects, error: NSError?) -> Void in
if error == nil {
}
}
I'm not sure how to use "objects" to download the array from that row.
To make things more clear, this should be the closure signature:
query.findObjectsInBackgroundWithBlock {
(objects : [PFObject]?, error: NSError?) -> Void in
if error == nil {
}
}
Then you can iterate through objects like:
for object in objects {
print(object)
}

Retrieving values from an empty array

I want the user to upload an image, and other users leave replies to that image. Everything works fine so far except if the row for that specific image object is empty, the app crashes.
fatal error: unexpectedly found nil while unwrapping an Optional value
Here is my code :
override func viewDidLoad() {
super.viewDidLoad()
var error = ""
var query = PFQuery(className:"Posts")
query.getObjectInBackgroundWithId(cellID) {
(objects: PFObject!, error: NSError!) -> Void in
if error == nil {
var array = objects.objectForKey("replies") as [String] // <- when error occurs the compiler point here.
for object in array {
self.repliesArray.append(object as String)
}
} else {
self.displayError("Error", error: "Error retreiving")
}
self.tableView.reloadData()
}
}
Does this work? You can't append null objects to an array so this appends an empty string instead of null. Also you need the explanation mark so that it can be nil.
var array = objects.objectForKey("replies") as [String!]
for object in array {
if object != nil {
self.repliesArray.append(object as String)
}
else {
self.repliesArray.append("")
}
}
query.getObjectInBackgroundWithId(cellID) {
(objects: PFObject!, error: NSError!) -> Void in
if error == nil {
var array = objects.objectForKey("replies") as [String] // <- when error occurs the compiler point here.
The key here is that you're accepting an implicitly unwrapped optional (PFObject!) which is implying a promise that it will never be nil, but is nil.
Ideally (*), the type should be (objects: PFObject?, error: NSError?) -> Void to make the optionals explicit and force you to do the nil checking that is required. I believe you can do this even if the caller claims to send you (PFObject!, NSError!) -> Void, since I think Swift will make the implicit->explicit conversion for you.
If that's still impossible, then you will have to manually verify that objects is not nil before using it. (This is unlike #Dehli's solution, which checks that the things contained in objects are non-nil. That's not the problem; the problem is that objects itself is nil.)
(*) I say "ideally" here in terms of the existing interface. Passing a tuple of optional value/error is a lousy pattern. The better solution is to use something like a Result object.

Resources