I'm trying to make a Query with a Pointer in Parse.
Basically I have two classes "commentsTable" and "_User", I want to get the comment of the user from class "commentsTable" on a determined post, and then get the username and the profile_pic from the class "_User"
_User Class
commentsTable Class
func loadAndShowComments(){
let query2 = PFQuery(className: "commentsTable")
query2.orderByDescending("createdAt")
query2.whereKey("newsColumns", equalTo: printteste!)
query2.includeKey("username")
query2.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if let objects = objects as [PFObject]? {
for object in objects {
print(object["commentColumn"])
}
}
for cardset in objects! {
var lesson = cardset["username"] as! PFObject
var name = lesson["username"] as! String
print("By user: \(name)")
}
I'm able to see the query, I print the result an I have the following output:
This is a post!
This is a test post!
By user: teste#teste.com
By user: mmachado
And in my app I display this informations inside a TableView, I'm successfully can show the results for the Query in the func cellForRowAtIndexPath:
if let usuarioComentario = object?["commentColumn"] as? String {
cell?.usuarioComentario?.text = usuarioComentario
}
But I'm no able to return the values of my other class, _User
I think I misunderstood some concept but at this point I don't know what concept, any ideas?
Thanks.
By using query2.includeKey("username") you are already retrieving all of the User data associated with each commentsTable object.
You can access the related User data using the following.
if let commentUser = object["username"] as? PFUser {
let name = commentUser["username"] as! String
let profilePicture = commentUser["profile_pic"] as! PFFile
}
You need to store the query results to an array for later use if you aren't already. If you are using Parse's provided PFQueryTableViewController this will be handled for you by implementing the queryForTable() method and the results are automatically stored in an array of dictionaries called objects.
It is also worth noting that you will have to still have to load the PFFile because they are not included in query results. You will want to assign the PFFile to a PFImageView and then call loadInBackground. See the example below.
let imageView = PFImageView()
// Set placeholder image
imageView.image = UIImage(named: "placeholder")
// Set remote image
imageView.file = profilePicture
// Once the download completes, the remote image will be displayed
imageView.loadInBackground { (image: UIImage?, error: NSError?) -> Void in
if (error != nil) {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
} else {
println("image loaded")
}
}
Lastly, I'd recommend changing the name of the User pointer within commentsTable from "username" to "user" so there is no confusion with the username field of the user class. Here's a link to a great tutorial which you may also find helpful
Related
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
I have a class called Posts in which i've postedBy column where i am saving the PFUser.currentUser() (pointer). so i want to retrieve the username, profile picture and stuff from the _User class using postedBy in the Posts class. What is the shortest and efficient way to achieve this? i am not much familiar with relation queries.
I believe that instead of saving the user pointer, you should save the user's username then it comes easier for you to retrieve everything.
var query = PFQuery(className:"Posts")
var username = PFUser.currentUser()?.username
query.whereKey("username", equalTo: username!)
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil
{
if let objects = objects as? [PFObject]
{
for one in objects {
var pictureImage = one["theFile"] as! PFFile
pictureImage.getDataInBackgroundWithBlock({ (dataToget:NSData?, error:NSError?) -> Void in
if error == nil {
if let Image = UIImage(data: dataToget!){
// then you have the image
// save the image to array
// reload the tableview
}
}
})
}
}
}
}
I'm trying to get the name of a Client that is owner of a Vitrine.
Here is my code.
To save the data I'm doing this:
self.vitrine["username"] = PFUser.currentUser()?.username
self.vitrine["name"] = nameTextField.text as String
var relation = self.vitrine.relationForKey("client")
relation.addObject(self.client)
self.vitrine.saveEventually { (success, error) -> Void in
if(error == nil){
}else{
println(error?.userInfo)
}
self.fetchAllVitrines()
self.navigationController?.popToRootViewControllerAnimated(true)
}
}
And it works. In the Parse I can see the relation working.
I'm trying to access data of relation doing this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("vitrineCell", forIndexPath: indexPath) as! VitrineTableViewCell
var object: PFObject = self.vitrineObjects.objectAtIndex(indexPath.row) as! PFObject
cell.nomeLabel.text = object["name"] as? String
let x: PFRelation = object["client"] as! PFRelation
// cell.clientNameTextView.text = object["client"]["name"] as String
return cell
}
But when I log the data inside client column is that what appear for me:
<PFRelation: 0x7b7f1390, 0x7b7cfdc0.client -> Client>
Please somebody helps me. I'm on that for 2 days. I read more than 3 times the Parse Doc. and I don't find a way to do that.
Regards,
Diogo Amaral
Well, I add the code:
query!.getFirstObjectInBackgroundWithBlock {
(object: PFObject?, error: NSError?) -> Void in
if error != nil || object == nil {
println("The getFirstObject request failed.")
} else {
println(object)
cell.clientNameTextView.text = object["name"] as? String
}
}
But the line: cell.clientNameTextView.text = object["name"] as? String
throws me an error. "Cannot assign a value of type 'String?' to a value of type 'String!'"...
I already tried:
cell.clientNameTextView.text = object["name"] as! String
cell.clientNameTextView.text = object["name"] as String
cell.clientNameTextView.text = object["name"] as? String
How do I can fix that?
If you're using a relation (rather than a pointer) then you need to be aware that relations store arrays of their destination objects. So, when you execute
var relation = self.vitrine.relationForKey("client")
relation.addObject(self.client)
you're adding self.client to the array of clients. If a vitrine can only have a single owner, and this should be stored in the client field, then you probably want to use a Pointer rather than a Relation.
Because of this array, your code as written just won't work. You need get the relation from your vitrine object, query it, extract the element from the array you want, and then you can use it.
let x: PFRelation = object["client"] as! PFRelation
let query = x.query()
// Lets say that you are only interested in the first element in your array...
query.getFirstObjectInBackgroundWithBlock { first, error in
// Should do error checking here
cell.clientNameTextView.text = first!.objectForKey("name") as? String
}
This method is also a bit inefficient. You should use some form of caching, or ideally, determine if you really do need to use a Relation or if a Pointer will suffice. If a Pointer will do, you can also include the data it points to when you run your original query via the includeKey method on PFQuery. You can't use includeKey on a Relation.
I am developing app using ios, swift and parse.com as backend.
My problem is I need one query object result in second query object like below code. but when i use below code GUI become unresponsive for some time because of findObjects() method. I have used findObjectsInBackgroundWithBlock() instead but than tableview self.posts display only one record in tableview. I have 10 record in post table.
Can you guide me proper way how to resolve below issue.Actually I does not want to use findObjects() method.
var query = PFQuery(className:"Post")
var fquery = PFQuery(className: "Friends")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
let user = PFUser.currentUser()
if let objects = objects as? [PFObject] {
for object in objects {
friendArray.removeAll(keepCapacity: false)
fquery.whereKey("whosefriend", equalTo: object["postusername"])
var fobjects = fquery.findObjects()
for fobject in fobjects {
friendArray.append(fobject["friendname"] as String)
}
if (contains(friendArray, user["fullname"] as String)) {
let post = Post(.......)
self.posts.append(post)
}
}
}
self.tableView.reloadData()
} else {
println("Error: \(error) \(error.userInfo!)")
}
}
One option is to make your "postusername" a pointer column in class Post that points to Friends class and then you would only need one query that would go something like:
var query = PFQuery(className:"Post")
query.includeKey("postusername") //this would include the object that it points to i.e. the Friends object you saved there
... then in your for loop ...
for object in objects! {
let friend = object["postusername"] // now friend is the Friends object
let friendName:String = friend["friendname"] as? String
friendArray.append(friendName)
}
Note: this requires you saving "postusername" as a PFObject of Class Friends. Parse iOS docs explain this well.
https://parse.com/docs/ios/guide
I have resolve the issue by using relational query.
var query = PFQuery(classWithName: "Post")
var fQuery = PFQuery(className:"Friends")
fQuery.whereKey("friendname", equalTo: cuser["fullname"])
query.whereKey("postusername", matchesKey:"whosefriend", inQuery:fQuery)
I am building a checkin app, and am having trouble filling my tableview with guests stored using Parse. I get an error when trying to append the objects. I also have a user login that I followed from a Udemy course. In the course he showed how to display PFUsers, but I can't get it to work using PFObjects. Any help would be great on this.
Here is the working code with PFUsers.
var users = [""]
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query!.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
self.users.removeAll(keepCapacity: true)
for object in objects! {
var user:PFUser = object as! PFUser
self.users.append(user.username!)
}
self.tableView.reloadData()
})
}
And here is the nonworking code with PFObjects.
var users = [""]
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "TestObject")
query.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
self.users.removeAll(keepCapacity: true)
for object in objects! {
var guest = object as! PFObject
self.users.append(guest.foo!)
}
})
}
The error shows on the line
self.users.append(guest.foo!)
And the error says "'PFObject' does not have a member named 'foo'"
You define your PFUser object with the variable user, this will make the first example work (you get the name of the user) The second example doesn’t work cause you still define the PFObject as user but try to access the name of guest which is not defined.
You could either go with the first example or change
var user:PFObject = object as! PFObject
With
var guest:PFObject = object as! PFObject
Either way, it doesn’t matter for your code, it is just the name of the variable.
This explanation will fix your “Use of unresolved identifier ‘guest’”
But this isn’t your only problem,
the PFUser object which the first example uses is a special kind of a PFObject, the PFUser class does have a .name which refers to (obviously) the name of the user. Not every PFObject has a name though so you can’t just access the .name of a PFObject. Parse has an excellent documentation about retrieving objects I would first access this documentation. If this is still unclear to you, you can open another specific question about your new problem.
To retreive the data from an object you need to use []
Let’s suggest we have a class named gameScore with the following info
score: 1337, playerName: “Sean Plott”, cheatMode: false
We would do that as follows
var gameScore = PFObject(className:"GameScore")
gameScore["score"] = 1337
gameScore["playerName"] = "Sean Plott"
gameScore["cheatMode"] = false
gameScore.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// The object has been saved.
} else {
// There was a problem, check error.description
}
}
To retrieve the object you need to query (as you already did in your post)
Ones you’ve received the data you can extract it as follows:
let score = gameScore["score"] as Int
let playerName = gameScore[“playerName"] as String
let cheatMode = gameScore["cheatMode"] as Bool
I figured it out, I needed to get the object label as a string before I could append it to the array to then add it to the tableview.
Here is the working code:
var users = [""]
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "TestObject")
query.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
self.users.removeAll(keepCapacity: true)
for object in objects! {
var foo = object.objectForKey("foo") as? String
self.users.append(foo!)
}
self.tableView.reloadData()
})
}