Parse.com Query to Get All Items with a Specific Pointer - ios

I want to get all items from my Parse.com table called Sticker, from a particular shop. My Sticker table has a column called shopId. So the obvious solution is this:
//get all stickers from one shop of category dress
var query = PFQuery(className:"Sticker")
query.whereKey("shopId", equalTo: "QjSbyC6k5C")
query.whereKey("category", equalTo: "DR")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
However that causes this error:
error: pointer field shopId needs a pointer value
I have seen a common solution for this seems to be to pass the query the actual object and not a string of the ID. Does this mean I have to first do a separate query to get the specific shop object, and then pass that to my query? Or is there a shorter way?
Here is my attempt to get the shop but it's causing this error:
Can only call -[PFObject init] on subclasses conforming to
PFSubclassing
var query1 = PFQuery(className: "Shop")
var shop1 = PFObject()
query1.getObjectInBackgroundWithId("QjSbyC6k5C") {
(shop: PFObject?, error: NSError?) -> Void in
shop1 = shop!
}
EDIT: So my solution was basically doing what the answer suggested. My code was this (Glamour is the name of the shop):
var shopQuery = PFQuery(className:"Shop")
shopQuery.getObjectInBackgroundWithId("QjSbyC6k5C") {
(glamour: PFObject?, error: NSError?) -> Void in
if error == nil && glamour != nil {
println(glamour)
//get all stickers from one shop of category dress
var query = PFQuery(className:"Sticker")
query.whereKey("shopId", equalTo: glamour!)
query.whereKey("category", equalTo: "DR")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
} else {
println(error)
}
}
I will leave this question here and maybe someone will answer with a comment: Is there any way to get the shop and give it class scope so that we do not have to nest the second query inside the success of the first query? Would that be more elegant?

You need to pass PFObject. change your code with following
PFObject *object = ...
var query = PFQuery(className:"Sticker")
query.whereKey("shopId", equalTo: "QjSbyC6k5C")
query.whereKey("category", equalTo: object);

Related

Random row in Parse

I am creating an app that involves questions and facts and I need them to be selected at random. There is going to be a ton of different ones and I do not want to have to type in the ObjectId for each one of them. Is there a way to get the ObjectId of a random row so I don't have to write in the object Id for each question or fact that is in the class?
Three steps to accomplish what you want:
Know ahead of time or find out the number of questions you have to look through.
Create a random integer using arc4random() or some other method between 0 and that number.
Create a PFQuery on your question class with skip set to the random integer and limit set to 1.
Here is a function for retrieving your questions, only the first 1000, and saving them locally:
func saveAllObjectsLocally() {
let query = PFQuery(className: “Questions”)
query.limit = 1000
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects {
do {
try PFObject.pinAllInBackground(objects)
} catch let error as NSError? {
print("error \(error)")
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
}
Once they are saved locally, a random question can be selected:
func getRandomQuestion() -> PFObject? {
let query = PFQuery(className: “Questions”)
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if let objects = objects {
let randomIndex = arc4random_uniform(UInt32(objects.count))
return objects[Int(randomIndex)]
}
}
return nil
}
This is going to be faster than accessing the network every time a random question is needed.
If you need to access the questions from the cloud you can add an index column to your Parse database and use that as a key to efficiently retrieve a random row.

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

How to put asynchronous Parse.com functions in a separate Class in Swift?

I am using Parse.com as my backend. I would like to put all functions/code related to accessing Parse.com in a single class that I can call from different ViewControllers.
Problem is that - since many of these functions from Parse.com are asynchronous, how does one return a value from these functions to update the UI?
For example, in the following function I am going and getting Earnings information of the current user. Since this function is using the asynchronous method findObjectsInBackgroundWithBlock from parse.com, I cannot really return anything from this function.
Is there a workaround to this problem? Currently, I am having to place this in function in the same ViewController class. (and hence having to repeat this same function in multiple viewControllers. Would like to have it in a single function only)
Only solution I see is to go to the synchronous method findObjects. Is there any other way?
func getcurrUserEarnings() {
/// Get details of currentUser from Earnings Class
///
/// :param - NSInterval
/// :returns - Int
func loadEarningsInfo() {
if (PFUser.currentUser() != nil) {
var query = PFQuery(className:"Earnings")
query.whereKey("user", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
//WANT TO UPDATE UI HERE WITH THE VALUES THAT WERE JUST RETURNED
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
}
}
}
You can use callback to pass in something.
For example:
func doSomething(callBack:(String)->())->(){
callBack("abc")
}
doSomething { (str:String) -> () in
println(str)
}
Also, do not forget to update UI on main thread
For example
func loadEarningsInfo(callBack:([PFObject])->()) {
if (PFUser.currentUser() != nil) {
var query = PFQuery(className:"Earnings")
query.whereKey("user", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
if let objects = objects as? [PFObject] {
callBack(objects)
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
}
}
Then when you use
loadEarningsInfo { (objects:[PFObject]) -> () in
//Update UI with objects
}
You can also handle error in callback as well,I just post a simple example

Getting empty username string

var query = PFQuery(className:"FriendRequest")
query.whereKey("receiver", equalTo: PFUser.currentUser())
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if let objects = objects as? [PFObject] {
self.friendRequestArray = objects
let user = self.friendRequestArray[0]["sender"] as PFUser
println(user.username) //prints blank string.
self.tableView.reloadData()
}
}
Hello, why is my println(user.username) printing nothing in this scenario? There are numerous objects in the array and ["sender"] points to a valid user.
What is going on?
edit: self.friendRequestArray is initialized earlier as [PFObject]()
edit2: No error is occurring either, since the error object is nil.
Add query.includeKey("sender") before you call findObjectsInBackgroundWithBlock.

Using parse to query info in Swift

I am currently trying to implement a parse database into a Swift app. I am having trouble understanding how to use the data, when you query from parse. Here is a query I am using:
var query = PFQuery(className: "CompanyInfo")
query.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]! , error: NSError!) -> Void in
if error == nil{
println("Successfully retrieved \(objects.count) specials.")
println(objects[0])
}else{
println(error)
}
})
So I know this works because it prints out all the data to the console.
Then when I do the objects[0] it prints out the first.
How would I use the objects to set data into my app? For instance, if I have a title section in my parse class CompanyInfo, how do I get that information for later on?
To get the objects as PFObjects just cast them..
query.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]! , error: NSError!) -> Void in
var myPFObjects = objects as? [PFObject] // now you have your array of pfobjects
})
To get any attribute/column of a pfobject just call it like this
var aPFObject = myPFObjects[0]
var title = aPFObject["title"] as? String
A better way to do all these things is to subclass the pfobject and get them via class properties, which would make following code:
The subclass..
class CompanyInfo: PFObject, PFSubclassing {
var title: String? {
get {
return self["title"] as? String
}
set {
self["title"] = newValue
}
}
class func parseClassName() -> String! {
return "CompanyInfo"
}
}
and the code where you call the query:
var cpQuery = CompanyInfo.query()
cp.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]! , error: NSError!) -> Void in
var myCompanyInfos = objects as? [CompanyInfo] //Directly cast them to your objects
for cp in myCompanyInfos {
println(cp.title) //print all the titles
}
})

Resources