I have the following function calling Parse written i swift:
func listCatalogItemsWithBlock(completion: (result: ([ParseCatalog], NSError)) -> Void)
{
let parseClassName = ParseCatalog.parseClassName()
let query = PFQuery(className: parseClassName)
query.findObjectsInBackgroundWithBlock { (ParseCatalog catalog, NSError error) -> Void in
}
}
What i want is to forward the result block of findObjectsInBackgroundWithBlock to listCatalogItemsWithBlock function's block, so i can process the results elsewhere.
How can i do that?
UPDATE 1
I have managed to do this quite easily:
func listCatalogItemsWithBlock(completion: PFQueryArrayResultBlock)
{
let parseClassName = ParseCatalog.parseClassName()
let query = PFQuery(className: parseClassName)
query.findObjectsInBackgroundWithBlock(completion)
}
But in this case i passed a PFQueryArrayResultBlock type. Which is:
public typealias PFQueryArrayResultBlock = ([PFObject]?, NSError?) -> Void
How do i return the same results if i keep my function the original way:
func listCatalogItemsWithCompletion(completion:([ParseCatalog]?, NSError?) -> Void)
/* What goes here? */
}
Update 2
Like this:
func listCatalogItemsWithCompletion(completion:(fvResponse: [ParseCatalog], fvError: NSError?) -> Void)
{
let parseClassName = ParseCatalog.parseClassName()
let query = PFQuery(className: parseClassName)
query.findObjectsInBackgroundWithBlock { (response:[PFObject]?, error: NSError?) -> Void in
completion(fvResponse: response as! [ParseCatalog], fvError: error)
}
}
Related
I have the following function that's suppose to pull images from a class in Parse. The number of images in the class is two and the print line print(objectsFound?.count) prints out 2 - confirming there are two images
func loadAllObjects() {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .NetworkElseCache
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
discoveryQuery.findObjectsInBackgroundWithBlock { (objectsFound: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
print(objectsFound?.count) //This prints out 2
for var i = 0; i < objectsFound?.count; i++ {
if let imageFileFound = objectsFound![i].objectForKey("workoutImage") as? PFFile {
imageFileFound.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
self.arrayOfWorkoutImages = [UIImage(data:imageData!)!]
}
}
}
}
} else {
//An error Occured
self.showFailureAlert("😐 Failed to get workout Images", detailedMessage: "Check your network settings and try again", buttonMessage: "Ok")
}
}
}
I want to load the images into an array where I can use them later.
The line self.arrayOfWorkoutImages = [UIImage(data:imageData!)!] adds them to the array
var arrayOfWorkoutImages: [UIImage] = []
On trying to see whether the images are pulled (checking the print(self.arrayOfWorkoutImages) and print(self.arrayOfWorkoutImages.count) ) I get only ONE image counted and pulled. This is the function I am using that is linked to a button that does this.
#IBAction func addbuttonPressed(sender: AnyObject) {
self.loadAllObjects()
print(self.arrayOfWorkoutImages)
print(self.arrayOfWorkoutImages.count)
}
Any ideas on what I could be doing wrong. This is has been throwing errors at me for a couple of days now!! :(
Your code contains an error: for each object you re-assign to arrayOfWorkoutImages an array with the retrieved image.
func loadAllObjects(completion: () -> Void) {
let discoveryQuery = PFQuery(className: "DiscoveryDetails")
discoveryQuery.cachePolicy = .NetworkElseCache
discoveryQuery.whereKey("discoveryID", equalTo: PFObject(withoutDataWithClassName: "Discovery", objectId: "\(varInDDT!.objectId!)"))
discoveryQuery.orderByDescending("createdAt")
discoveryQuery.findObjectsInBackgroundWithBlock { (objectsFound: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for var i = 0; i < objectsFound?.count; i++ {
if let imageFileFound = objectsFound![i].objectForKey("workoutImage") as? PFFile {
imageFileFound.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
if let data = imageData, image = UIImage(data: data) {
self.arrayOfWorkoutImages.append(image)
}
}
}
}
}
}
completion()
}
}
I want to retrieve the user score from Parse and assign it to a variable. This function returns 0 before the query finishes. I have found a similar answer at Retrieve object from parse.com and wait with return until data is retrieved. However, I expect the function have a return value and what argument should I use for the completionhandler when calling this function. Any help would be appreciated, thanks!
Here is my code
func loadCurrentUserData() -> Int {
let query = PFQuery(className: "userScore")
let userId = PFUser.currentUser()!
var currentUserScore: Int = 0
query.whereKey("user", equalTo: userId)
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
let scoreReceived = objects![0]["score"] as! Int
currentUserScore = scoreReceived
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.userScore.text = "\(scoreReceived)"
})
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
return currentUserScore
}
The way you have set this function will not work as the query method is asynchronous. This can be fixed in two ways:
1) Use the PFQuery synchronous category:
http://parse.com/docs/ios/api/Categories/PFQuery(Synchronous).html
The only disadvantage to this approach is that the method will become blocking so make sure to call it from a background thread.
2) Restructure the function to use a completion block instead of a return value..i.e:
func loadCurrentUserData(completion: (score: Int!, error: NSError?) ->()) {
let query = PFQuery(className: "userScore")
let userId = PFUser.currentUser()!
var currentUserScore: Int = 0
query.whereKey("user", equalTo: userId)
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
let scoreReceived = objects![0]["score"] as! Int
currentUserScore = scoreReceived
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.userScore.text = "\(scoreReceived)"
})
completion(score: currentUserScore, error: nil);
} else {
print("Error: \(error!) \(error!.userInfo)")
}
completion(score: currentUserScore, error: error);
}
}
In the user class I have a pointer "Friendship" to the user class, but when I run the program I get the error -
EDIT: I have figured out why I get the error. "Frinendship is not a pointer, it is a PFRelation, but I still want to access the ProPic and username. How would I do this?
Below is the user class
Below is the Pointer to the user class.
func getFriendPic(){
let imagequery = PFQuery(className: "_User")
imagequery.whereKey("username", equalTo: PFUser.currentUser()!)
imagequery.includeKey("Friendship")
imagequery.findObjectsInBackgroundWithBlock {( objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects!{
let userPic = object["ProPic"] as! PFFile
userPic.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if(error == nil){
let image = UIImage(data: imageData!)
self.arrayOfFriends.append(image!)
print(self.arrayOfFriends)
}
// dispatch_async(dispatch_get_main_queue()) {
// self.collectionView.reloadData()
// }
})
}
}
}
func getFriendName(){
var query = PFQuery(className: "_User")
query.whereKey("username", equalTo: PFUser.currentUser()!)
query.includeKey("Friendship")
query.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]?, error: NSError?) -> Void in
var objectIDs = objects as! [PFObject]
for i in 0...objectIDs.count-1{
self.arrayOfFriendsNames.append(objectIDs[i].valueForKey("username") as! String)
print(self.arrayOfFriendsNames)
}
})
}
The include query parameter doesn't work with Relation. Once you retrieved your user, you need to execute a second query to get the Friendship.
Here's an example to retrieve a PFRelation:
var relation = user.relationForKey("Friendship")
relation.query().findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if let error = error {
// There was an error
} else {
// objects contains the friendships of the user
}
}
I'm trying to use the getObjectInBackgroundWithId method, of a PFObject and it throws this error:
"Cannot invoke 'getObjectInBackgroundWithId' with an argument list of type (string, block: (PFObject!,NSError?) -> Void"
I have written the below code:
var result = PFQuery(className: "posts")
result.getObjectInBackgroundWithId("kk", block: {
(object: PFObject, error: NSError?) -> Void in
object["pLikes"] = object["pLikes"] + 1
object.save()
})
Any help?
You have to use getObjectInBackgroundWithId with
let query = PFQuery(className: "posts")
query.getObjectInBackgroundWithId("kk") { (objects, error) -> Void in
}
OR
let query = PFQuery(className: "posts")
query.getObjectInBackgroundWithId("kk") { (objects:PFObject?, error:NSError?) -> Void in
}
Change the object
let query = PFQuery(className: "posts")
query.getObjectInBackgroundWithId("kk") { (objects, error) -> Void in
let testObj = objects?.first as! PFObject
testObj.setObject(26, forKey: "pLikes")
testObj.saveInBackgroundWithBlock { (succeeded, error) -> Void in
if succeeded {
println("Object Uploaded")
} else {
println("Error: \(error) \(error!.userInfo!)")
}
}
}
All,
I have a simple class in the parse backend - which feeds a uitableview. The data is stored in Arrays. I guess because all parse data is done in the background sometimes data gets downloaded before others. I have a very mixed up tableview. With images in the wrong cell etc. Also the custom cells are sometimes not showing up at all and I need to do a refresh.
Here is my code that I used to download all the data from parse and add into the arrays.
Can you have a look please and suggest a way to do this.
Also how can I add a placeholder image , before the original image comes up.
Also this code is in my ViewDidLoad, would it be better in an earlier function, hopefully so i don't have to relsoaddata on the tableview..
var query = PFQuery(className:"TableViewData")
query.includeKey("EventLoc")
query.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for object in objects {
let thumbNail = object["backgroundImage"] as PFFile
thumbNail.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data:imageData)
self.CellBackgroundImage.append(image!)
}
}
})
var VenueLocation = object["EventLoc"] as PFObject!
VenueLocation.fetchIfNeededInBackgroundWithBlock {
(VenueLocation: PFObject!, error: NSError!) -> Void in
dispatch_async(dispatch_get_main_queue()) {
let VenueLocationTitle = VenueLocation["EventLocation"] as NSString
self.EventLocationArray.append(VenueLocationTitle)
}
}
let eventiconimage = object["EventIcon"] as PFFile
eventiconimage.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data:imageData)
self.EventIconImageArray.append(image!)
}
}
})
dispatch_async(dispatch_get_main_queue()) {
self.TitleArray.append(object["EventTitle"] as String)
self.EventPriceArray.append(object["EventPrice"] as String)
self.EventStartDate.append(object["EventStartDate"] as NSDate)
self.EventEndDate.append(object["EventEndDate"] as NSDate)
self.tableView.reloadData()
}
You need to use serial queue then your array data will be in order. Whats happening because of concurrent task the data is not appended in order
var backgroundQueue:dispatch_queue_t = dispatch_queue_create("SerialQueue", DISPATCH_QUEUE_SERIAL)
var query = PFQuery(className:"TableViewData")
query.includeKey("EventLoc")
query.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for object in objects {
dispatch_async(backgroundQueue, { () -> () in
let thumbNail = object["backgroundImage"] as PFFile
thumbNail.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data:imageData)
self.CellBackgroundImage.append(image!)
}
}
})
var VenueLocation = object["EventLoc"] as PFObject!
VenueLocation.fetchIfNeededInBackgroundWithBlock {
(VenueLocation: PFObject!, error: NSError!) -> Void in
dispatch_async(dispatch_get_main_queue()) {
let VenueLocationTitle = VenueLocation["EventLocation"] as NSString
self.EventLocationArray.append(VenueLocationTitle)
}
}
let eventiconimage = object["EventIcon"] as PFFile
eventiconimage.getDataInBackgroundWithBlock({
(imageData: NSData!, error: NSError!) -> Void in
if (error == nil) {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data:imageData)
self.EventIconImageArray.append(image!)
}
}
})
dispatch_async(dispatch_get_main_queue()) {
self.TitleArray.append(object["EventTitle"] as String)
self.EventPriceArray.append(object["EventPrice"] as String)
self.EventStartDate.append(object["EventStartDate"] as NSDate)
self.EventEndDate.append(object["EventEndDate"] as NSDate)
self.tableView.reloadData()
}
});
}
}