I am trying to query my Parse "User" table using a objectId to get a specific row.
However I kept getting this error:
2016-01-08 22:03:50.476 ParseStarterProject-Swift[6278:3821859] [Error]: No results matched the query. (Code: 101, Version: 1.11.0)
Why is parse saying there is no results matched when the userObjectId var is clearly found in the objectId column of the Parse "User" table?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cell = tableView.cellForRowAtIndexPath(indexPath)
//place checkmark
cell!.accessoryType = UITableViewCellAccessoryType.Checkmark
//getting selected user parse objectId
var userObjectId = userStructArray[indexPath.row].userId
print(userObjectId) //prints hvPpO9XXtY
var userQuery = PFQuery(className: "User")
userQuery.getObjectInBackgroundWithId(userObjectId) { (userObject, error) -> Void in
if error == nil && userObject != nil {
print(userObject)
} else {
//print(error)
}
}
}
Thanks for your help.
Change this line
var userQuery = PFQuery(className: "User")
To
var userQuery = PFQuery(className: "_User")
Related
I am trying to count the number of the found objects in PFQueryTableViewController.
I have tried working around with
override func queryForTable() -> PFQuery {
let query = PFQuery(className: self.parseClassName!)
query.whereKey("member", equalTo: memberId!)
let count = query.countObjectsInBackground()
label.text = "\(count)"
return query
}
But my app will crash.
EDIT:
The issue is not to make a query and count it's objects. The problem is to use queryForTable passing my query to cellForRowAtIndexPath of my PFQueryTableViewController
the cellForRowAtIndexPath looks like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
let cell:DetailApplicantCell = self.table.dequeueReusableCellWithIdentifier("reuseIdentifier") as! DetailApplicantCell
if let name = object?.objectForKey(self.textKey!) as? String{
cell.nameLbl.text = name
}
cell.groupImage.image = UIImage(named: "People.png")
if let imageFile = object?.objectForKey(self.imageKey!) as? PFFile{
cell.groupImage.file = imageFile
cell.groupImage.loadInBackground()
}
return cell
}
NOTE that this is not the default cellForRow
Try with query.findObjectsInBackgroundWithBlock method and get the size() of the response object
let query = PFQuery(className: self.parseClassName!)
query.whereKey("member", equalTo: memberId!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
let count = objects.size()
label.text = "\(count)"
if let object = objects as? [PFObject] {
}
} else {
// Log details of the failure
print("Error: \(error!)")
}
}
You are force unwrapping at 2 places, use if let:
func queryForTable() -> PFQuery? {
if let parseClass = self.parseClassName {
let query = PFQuery(className: parseClass)
if let id = memberId {
query.whereKey("member", equalTo: id)
}
let count = query.countObjectsInBackground()
label.text = "\(count)"
return query
}
return nil
}
Then you use your function like:
if let query = queryForTable() {
//your query related code here.
}
Rather than doing a second PFQuery I found a better way using a method of PFQueryTableViewController like this:
override func objectsDidLoad(error: NSError?) {
super.objectsDidLoad(error)
print("objectsDidLoad")
if let results = self.objects{
print("objectsFound")
self.groupsCountLbl.text = "\(results.count)"
self.groupsCountLbl.fadeIn()
}
}
The VC has a property objects an array of AnyObject?.
With the objectsDidLoad function you determine the time, everything is loaded.
I am trying to create an array of strings for all the usernames using the following code and populate a TableViewController.
class TableViewController: UITableViewController {
var randomUser = [String]()
override func viewDidLoad() {
super.viewDidLoad()
var query: PFQuery = PFUser.query()!
query.findObjectsInBackgroundWithBlock {(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil{
if let objects = (objects as? [PFObject]!){
for object in objects{
self.randomUser.append(object.objectForKey("username") as! String)
print(object.objectForKey("username") as! String)
print(self.randomUser.count)
}
}
}
}
print(self.randomUser.count)
}
the output in the console:
0
username
1
username
2
username
3
But UItableview does not populate.. What could be causing this?
My guess is that query is delayed and view is created before it can return data. Thank you for any help!
Yes, you are right. You need to call self.tableView.reloadData() after you get the results of the query. Below is an example of where to call it.
private var usersArray = [PFUser]()
func fetchUsers() {
let userQuery: PFQuery = PFUser.query()!
userQuery.orderByAscending("username")
userQuery.whereKey("username", notEqualTo: (currentUser?.username)!)
userQuery.findObjectsInBackgroundWithBlock({
(users, error) -> Void in
if error == nil {
self.usersArray = users as! [PFUser]
self.tableView.reloadData()
} else {
print(error)
}
})
}
In this example, you can then access the username property by doing usersArray[i].username
I'm adding a friendship relation for current user to the row which resembles another user in user table using table view controller.
I cannot find a way of setting the selected row as a variable, in this instance the object would be called user. The way I currently have throws up an error on the objectAtIndex part.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
var relation : PFRelation = PFUser.currentUser().relationForKey("friendship")
let user:PFObject = self.userArray.objectAtIndex(indexPath.row) as PFObject
relation.addObject(user)
PFUser.currentUser().saveInBackgroundWithBlock { (succeed:Bool, error: NSError!) -> Void in
if error != nil {
NSLog("Unable to save")
}
}
}
The error that is thrown underlines objectAtIndex and says, "String does not have a member named 'objectAtIndex'."
I've looked at numerous tutorials and read through lots of documentation and can't find a fix. Any help would be great.
Thanks,
Chris
userArray is defined here..
var userArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query.whereKey("username", notEqualTo: PFUser.currentUser().username)
var users = query.findObjects()
for user in users {
userArray.append(user.username)
}
}
I noticed there are many questions on this in Obj-C but I hardly remember Obj-C and each of the answers was specific to the question. Here I get this error: "No index path for table cell being reused" sometimes when the app refreshes. I notice that when I don't refresh but I leave and reopen the table view the formatting is ruined.
Here is my "refresh" method used in a few places:
#IBAction func loadData(){
timeLineData.removeAllObjects()
//pulls the data from the server
var findTimeLineData: PFQuery = PFQuery(className: "Sweets")
findTimeLineData.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]!, error: NSError!) -> Void in
if !error{
for object:PFObject! in objects{
self.timeLineData.addObject(object)
}
let tempArray: NSArray = self.timeLineData.reverseObjectEnumerator().allObjects
self.timeLineData = tempArray as NSMutableArray
//reloads the data in the table view
self.tableView.reloadData()
}
}
}
And the tableview method:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell? {
let cell: SweetTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as SweetTableViewCell
let sweet: PFObject = self.timeLineData.objectAtIndex(indexPath.row) as PFObject
//part of the animation
cell.sweetTextView.alpha = 0
cell.userNameLabel.alpha = 0
cell.timestampLabel.alpha = 0
cell.sweetTextView.text = sweet.objectForKey("content") as String
//add the date
var dateFormatter: NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm yyyy-MM-dd"
cell.timestampLabel.text = dateFormatter.stringFromDate(sweet.createdAt)
//finds the sweeter associated with a pointer
var findSweeter: PFQuery = PFUser.query()
findSweeter.whereKey("objectId", equalTo: sweet.objectForKey("sweeter").objectId)
findSweeter.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]!, error: NSError!)-> Void in
if !error{
let user: PFUser = (objects as NSArray).lastObject as PFUser
cell.userNameLabel.text = user.username
}
}
//adds animation
UIView.animateWithDuration(1, animations: {
cell.sweetTextView.alpha = 1
cell.userNameLabel.alpha = 1
cell.timestampLabel.alpha = 1
})
return cell
}
Any idea what is causing the error?
What's causing the problem for you: when you scroll your table, the TableView dequeues the cell that your async call to parse server is trying to manipulate.
You can overcome this problem by:
1- in your Sweets table on Parse, store PFUser object as a pointer
2- in your loadData function, fetch user from the query by includeKey method of PFQuery
If you change according to this, you won't have to query the PFUser every time the cellForRowAtIndexPath is called.
The code below runs fine on the simulator then crashes on two devices and works on one device.
I'm also getting this:
function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded> of Swift.(_fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> ()).(closure #2)
Would it possibly have to do with bridging obj-C into my swift application?
Any suggestions
var query = PFUser.query()
query?.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
var users = query?.findObjects()
//Loop through users
if let users = users as? [PFUser]{
for user in users {
//println(user.username)
self.userArray.append(user.username!)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
cell.textLabel?.text = userArray[indexPath.row]
return cell
}
You want to perform the query in the background so the UI (main thread) stays responsive. Try the following:
if let currentUsername = PFUser.currentUser()?.username {
var query = PFUser.query()!
query.whereKey("username", notEqualTo: currentUsername)
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if (error == nil) {
if let users = objects as? [PFUser] {
for user in users {
self.userArray.append(user.username!)
}
}
} else {
// Log details of the failure
println("query error: \(error) \(error!.userInfo!)")
}
}
}
The first place I'd look is the forced unwrap of the optionals. Every one of those is asking for a crash -- when PFUser.currentUser() returns nil and user.username returns nil:
Try:
var query = PFUser.query()
if let query = query,
currentUser = PFUser.currentUser() as? PFUser,
currentUsername = currentUser.username {
query.whereKey("username", notEqualTo: currentUsername)
var users = query.findObjects()
//Loop through users
if let users = users as? [PFUser]{
for user in users {
//println(user.username)
if let username = user.username {
self.userArray.append(username)
}
}
}