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.
Related
In the overall scheme of things I am trying to compare the user's multiple selections from a tableview and compare them to my Parse database. So my problem is twofold 1. Is my current code going about it the correct way? and 2. How can I convert value type Bool to argument type PFObject?
Cannot convert value of type '() -> Bool' to expected argument type 'PFObject'
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showResults" {
// Get reference to destination view controller
let destination = segue.destinationViewController as! CollectionViewController
if let selectedItem = tableView.indexPathsForSelectedRows{
for var i = 0; i < selectedItem.count; ++i {
var currentPath = selectedItem[i] as NSIndexPath
var cell = tableView.cellForRowAtIndexPath(currentPath)
if let cell = cell {
//add major(s) selected to data variable in collectionview as type text(String)
destination.data.append(cell.textLabel!.text!)
}
let imagesQuery = PFQuery(className:"CollegeImages")
imagesQuery.selectKeys(["name"])
imagesQuery.findObjectsInBackgroundWithBlock({(objects: [PFObject]?, error: NSError?) in
if error == nil {
if let returnedobjects = objects {
//objects array isn't nil
//loop through the array to get each object
for object in returnedobjects {
print(object["name"] as! String)
}
}
}
})
let majorSelected:String = (cell?.textLabel!.text!)!
let query = PFQuery(className:"CollegeMajors")
query.selectKeys(["Major"])
query.findObjectsInBackgroundWithBlock ({
(objects: [PFObject]?, error: NSError?) in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(objects!.count) majors.", terminator: "")
// Do something with the found objects
if let returnedobjects = objects {
if returnedobjects.contains ({($0["Major"] as? String)! == majorSelected}) && query.selectKeys(["College Name"]) == imagesQuery.selectKeys(["name"]) {
print("your in!") // transition to the new screen
}
else {
print("your out.") // do whatever
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)", terminator: "")
}
})
}
}
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//Keep track of which major(s) the user selected
let path = tableView.indexPathForSelectedRow!
if let cell = tableView.cellForRowAtIndexPath(indexPath){
//Trigger the segue to go to the collection view
self.performSegueWithIdentifier("showResults", sender: self)
}
}
Your line of interest holds several problems.
First of all, you are passing a closure {["returnedobjects"] as? String == path } to contains(_:) method, but the closure does not take any arguments. You need to pass a closure taking one argument, where its type being the same as the element of the array.
Second, inside the closure, ["returnedobjects"] is an array, so, ["returnedobjects"] as? String always fails and generates nil. You need to change this part to a meaningful expression producing String, you may need to utilise the PFObject instances passed to this closure.
Third, you declare path as:
let path = tableView.indexPathForSelectedRow!
which means the local variable has type NSIndexPath. So, even if the left hand side of == returns a valid String, you cannot compare String to NSIndexPath. You may need to get a String value before comparing.
With considering all three above and with some guess, you need to:
Add one line below let path = ...
let majorSelected: String = (Some expression to retrieve "major" from the `path`)
Change the closure in the line containing contains as:
if returnedobjects.contains ({$0["Major"] as? String == majorSelected }) {
I am in the process of updating all my swift syntax after updating to xcode 7.3
In the process, I got some errors about ambiguous use of subscript swift and I believe that this error is also causing the Signal Fault.
The code in question:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var arry:NSArray = Array(self.participants)
arry = arry.sort {
item1, item2 in
// ambiguous use of subscript swift error for both these lines
let date1 = item1["fullName"] as String
let date2 = item2["fullName"] as String
return date1 > date2
}
Edit
Declaration of participants comes from another controller here:
func gotoMembers(){
let set:NSSet = self.conversation.participants
let arr = set.allObjects //Swift Array
UserManager.sharedManager.queryForAllUsersWithCompletion(arr as! [String], completion:{ (users: NSArray?, error: NSError?) in
if error == nil {
//participants declared here and passed into the participant controller
let participants = NSSet(array: users as! [PFUser]) as Set<NSObject>
let controller = ParticipantTableViewController(participants: participants, sortType: ATLParticipantPickerSortType.FirstName)
controller.delegate = self
self.navigationController?.pushViewController(controller, animated:true);
} else {
appDelegate.log.error("Error querying for All Users: \(error)")
}
})
}
Update
First of all use Swift native types a much as possible, for example the type of the contents of an NSArray object is unspecified.
Second of all use type annotations as few as possible, in the case
var array = Array(self.participants)
without an annotation you get a Swift Array for free and the compiler knows the type of the contents which is PFUser. The function sortInPlace() sorts the array itself without a return value and you have to forced downcast the fullName values to String
array.sortInPlace {
user1, user2 in
let date1 = user1["fullName"] as! String
let date2 = user2["fullName"] as! String
return date1 > date2
}
and use the proper type Set<PFUser> rather then Set<NSObject> and probably users: [PFUser]? in the completion handler rather then users: NSArray?
Edit: The beginning of the queryForAllUsersWithCompletion method is supposed to look like
UserManager.sharedManager.queryForAllUsersWithCompletion(arr as! [String], completion:{ (users: [PFUser]?, error: NSError?) in
if error == nil {
//participants declared here and passed into the participant controller
let participants = Set<PFUser>(array: users!)
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
I have a Parse query that returns a set of users (PFUsers). I place them in an array so that they can be used to populate a tableView. However, when I load the tableView I get the following error message: Could not cast value of type 'PFObject' to 'NSArray'. Here's the relevant code (I cut out some stuff to make it easier to read). It's heavily condensed but I can create a full gist of needed.
The error is caught on the line: self.realMatches = result as! [PFObject]
import UIKit
class MatchesViewController: BaseViewController {
var realMatches: [PFObject] = []
func loadMatches() {
if let user = self.user {
query{
(results: [AnyObject]?, error: NSError?) -> Void in
if error != nil {
println(error)
} else {
if results != nil {
self.matchesResults = results!
for result in results!{
if result.objectId != self.currentUser!.objectId {
self.realMatches = result as! [PFObject]
}
}
for result in results! {
self.user1 = result["user1"] as! PFUser
self.user2 = result["user2"] as! PFUser
}
self.tableView.reloadData()
}
}
}
} else {
println("current user doesnt exist")
}
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MatchCell", forIndexPath: indexPath) as! UITableViewCell
let object = matchesResults[indexPath.row]
return cell
How can I safely store the PFUsers in an array to be used for the tableView?
Thanks!!
result is a single PFObject that you have extracted from the array of results array using a for loop.
You should simply say
self.realMatches = result as! PFObject
but self.realMatches is an array, so that assignment won't work either. You can append the result to the array using
self.realMatches.append(result as! PFObject)
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
}
}
})
}
}
}
}