I have seen the following questions.
Get data from a pointer's row in Parse (ios)
and various other questions but still unable to figure out.
I have a class in Parse called 'Plumber'
As you can see the 'practiceArea' is a pointer to this class called 'PracticeArea' (mind the uppercase P in the class)
So from here I want to extract the corresponding 'title' column value for the corresponding pointer. How can I do this?
This is my code so far
//
// Directory.swift
// plumber_main
//
// Created by James on 13/4/16.
// Copyright © 2016 James. All rights reserved.
//
import UIKit
import Parse
class Directory: UITableViewController {
#IBOutlet var plumbersDirectory: UITableView!
var profImages = [PFFile]()
var plumberName = [String]()
var plumberRate = [NSNumber]()
var plumberPracArea = [PFObject]()
var plumberExp = [String]()
var refresher: UIRefreshControl!
func refresh()
{
let query_one = PFQuery(className: "PracticeArea")
query_one.includeKey("title")
let query = PFQuery(className: "plumber")
query.includeKey("practiceArea")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock(
{
(listll: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(listll!.count) names of the plumbers.")
// Do something with the found objects
if let objects = listll {
for object in objects {
print(object)
self.profImages.append(object["photo"] as! PFFile)
self.plumberName.append(object["name"] as! String)
self.plumberExp.append(object["expLevel"] as! String)
self.plumberPracArea.append(object["practiceArea"] as! PFObject)
print(object ["practiceArea"].objectId)
self.plumberRate.append(object["ratePerHr"] as! NSNumber)
// print(object["plumber_Name"] as! String )
// self.plumbersname.append(object["plumber_Name"] as! String)
//self.lblName.text = object["plumber_Name"] as? String
}
self.plumbersDirectory.reloadData()
}
print(self.plumberName.count)
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
self.tableView.reloadData()
self.refresher.endRefreshing()
})
}
override func viewDidLoad() {
super.viewDidLoad()
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to refrehsh")
refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
refresh()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return plumberName.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let plumbercell: plumber_Directory_Cell = tableView.dequeueReusableCellWithIdentifier("plumberlistproto") as! plumber_Directory_Cell
plumbercell.name.text = plumberName[indexPath.row]
plumbercell.exp.text = plumberExp[indexPath.row]
plumbercell.pracArea.text = String(plumberPracArea[indexPath.row])
plumbercell.price.text = String (plumberRate[indexPath.row])
profImages[indexPath.row].getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if imageData != nil {
let image = UIImage(data: imageData!)
plumbercell.mini_image.image = image
}
else
{
print(error)
} }
//cell.textLabel?.text = plumbersname[indexPath.row]
return plumbercell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
print(indexPath.row)
}
}
Try this
func refresh()
{
let query = PFQuery(className: "PracticeArea")
query.includeKey("practiceArea")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock( {
(listll: [PFObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(listll!.count) names of the plumbers.")
// Do something with the found objects
if let objects = listll {
self.plumberName = objects
} else {
self.plumberName.removeAllObjects()
}
self.plumbersDirectory.reloadData()
print(self.plumberName.count)
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
})
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let plumbercell: plumber_Directory_Cell = tableView.dequeueReusableCellWithIdentifier("plumberlistproto") as! plumber_Directory_Cell
let object = plumberName[indexPath.row]
plumbercell.name.text = object["name"]
plumbercell.exp.text = object["expLevel"]
let practiceArea = object["practiceArea"]
plumbercell.pracArea.text = practiceArea["title"]
plumbercell.pracArea.text = String(plumberPracArea[indexPath.row])
plumbercell.price.text = String (plumberRate[indexPath.row])
profImages[indexPath.row].getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if imageData != nil {
let image = UIImage(data: imageData!)
plumbercell.mini_image.image = image
}
else
{
print(error)
} }
//cell.textLabel?.text = plumbersname[indexPath.row]
return plumbercell
}
You were really close and definitely not "doing it all wrong". Since you've already included the key in the query request, when you want the information from that object too, then you just need this
let practiceArea = object["projectArea"] as! PFObject
let title = practiceArea["title"] as? String
you should query the different class if you want to use the pointer with the "includeKey"...
let query: PFQuery = PFQuery(className: "PracticeArea")
query.orderByDescending("createdAt")
query.includeKey("practiceArea")
query.findObjectsInBackgroundWithBlock{
(objects:[PFObject]?, error:NSError?)->Void in
if error == nil{
for object in objects! {
//do stuff with each object
}
}
}
Related
I am using this code to create a feed view that shows users, images, and comments similar to instagram. For some reason, the cells on the feed are duplicating the current user's posts. Not only that, but it is also putting the incorrect username with the images on the duplicate cells. What am I doing wrong?
import UIKit
import Parse
class FeedTableViewController: UITableViewController {
var usersBeingFollowed = [String]()
var imageFiles = [PFFile]()
var imageComment = [""]
var usernames = [String]()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true
let getFollowedUsersQuery = PFQuery(className: "Followers")
getFollowedUsersQuery.whereKey("follower", equalTo: PFUser.currentUser()!.objectId!)
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
self.usernames.removeAll(keepCapacity: true)
self.imageComment.removeAll(keepCapacity: true)
self.imageFiles.removeAll(keepCapacity: true)
self.usersBeingFollowed.removeAll(keepCapacity: true)
if let objects = objects {
for object in objects {
let followedUser = object["following"] as! String
let getFollowedUsers = PFQuery(className: "Post")
getFollowedUsers.whereKey("userId", equalTo: followedUser)
let getCurrentUser = PFQuery(className: "Post")
getCurrentUser.whereKey("userId", equalTo: (PFUser.currentUser()?.objectId)!)
var query = PFQuery.orQueryWithSubqueries([getFollowedUsers,getCurrentUser])
query.findObjectsInBackgroundWithBlock({ (imageObjects, error) -> Void in
if let objects = imageObjects {
for images in objects {
let userQuery = PFUser.query()
userQuery?.whereKey("_id", equalTo: images["userId"])
userQuery?.findObjectsInBackgroundWithBlock({ (user, error) -> Void in
print(user)
if let user = user {
for username in user {
self.usernames.append(username["username"] as! String)
}
}
})
self.imageFiles.append(images["imageFile"] as! PFFile)
self.imageComment.append(images["imageComment"] as! String)
self.tableView.reloadData()
}
}
})
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("imagePostCell", forIndexPath: indexPath) as! cell
if imageFiles.count > 0{
myCell.userLabel.text = "\(usernames[indexPath.row]) completed the \(imageComment[indexPath.row]) challenge!"
imageFiles[indexPath.row].getDataInBackgroundWithBlock({ (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.imagePost.image = downloadedImage
// self.tableView.reloadData()
}
})
}
return myCell
}
You should reset the cell property before add new values, you can use
prepareForReuse()
More info on Apple Doc https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableViewCell_Class/index.html#//apple_ref/occ/instm/UITableViewCell/prepareForReuse
It will be obviously, generate the duplicate content because you have put the condition that if imageFiles.count > 0 then the data will be displayed.
But what when there are no images? It will definitely take the value from reusable UITableViewCell. Check the below change:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("imagePostCell", forIndexPath: indexPath) as! cell
if imageFiles.count > 0{
myCell.userLabel.text = "\(usernames[indexPath.row]) completed the \(imageComment[indexPath.row]) challenge!"
imageFiles[indexPath.row].getDataInBackgroundWithBlock({ (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.imagePost.image = downloadedImage
// self.tableView.reloadData()
}
})
}else{
myCell.userLabel.text = "Put What You Want Here" //make just nil
myCell.imagePost.image = UIImage(name: "placeholder.png") //Some Placeholder image when there is no data
}
return myCell
}
I'm trying to save images from Parse to a variable called image stored which I can then set to tableview cells. At the moment I just have the images from parse being saved to a PFImageView. But when I try to set these to Table View Cells I get an error : Cannot assign value of type 'PFImageView' to type 'UIImage?' . Really appreciate any help.
Here's my code:
import UIKit
import Parse
import Bolts
import ParseUI
class YourEvents: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var currentuser = PFUser.currentUser()?.username
//array
var testArray = [String]()
var testdecr = [String]()
var image = UIImage()
var imagestored = PFImageView()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className:"Companies")
let pUserName = PFUser.currentUser()?["username"] as? String
query.whereKey("createdby", equalTo:"\(pUserName)")
// let runkey = query.orderByAscending("companyname")
query.findObjectsInBackgroundWithBlock{
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
//do something with the found objects
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("companyname") as! String
self.testArray .append(load)
print(self.testArray)
let load2 = object.objectForKey("companydescription") as! String
self.testdecr.append(load2)
print(self.testdecr)
if let userImageFile = object["imagefile"] as? PFFile {
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
self.image = UIImage(data:imageData)!
}
}
}
}
}
}
} else {
//log details of failure
print("Error: \(error!) \(error?.userInfo) ")
}
}
// reload UIViewController and UITabkeView
sleep(3)
do_table_refresh()
}
func do_table_refresh () {
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("yourstartups", forIndexPath: indexPath) as! YourStartupsCell
cell.lbTitle!.text = self.testArray[indexPath.row]
cell.lbDescription!.text = self.testdecr[indexPath.row]
cell.logo!.image = self.imagestored
return cell
}
}
In your code you never initialize imagestored (PFImageView) but only image (UIImage). try to change in to
cell.logo!.image = self.image
I no have idea if PFImageView has any
PFImageView.image
instances, than should be UIImage() class.
Also you should have something like this:
if let userImageFile = object["imagefile"] as? PFFile {
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
self.image = UIImage(data:imageData)!
var img = UIImage(data:imageData)
image.append(img)
self.tableView.reloadData()
}
}
}
Try to set the image to UIImage and call do_table_refresh() at the next line
I have my tableview returning titles, their descriptions and now I am trying to return images. It currently returns only one image for all of my cells. Is this because I'm storing it in a UIImage?
Here's my code:
import UIKit
import Parse
import Bolts
import ParseUI
class YourEvents: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var currentuser = PFUser.currentUser()?.username
//array
var testArray = [String]()
var testdecr = [String]()
var image = UIImage()
// var imagestored = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className:"Companies")
let pUserName = PFUser.currentUser()?["username"] as? String
query.whereKey("createdby", equalTo:"\(pUserName)")
// let runkey = query.orderByAscending("companyname")
query.findObjectsInBackgroundWithBlock{
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
//do something with the found objects
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("companyname") as! String
self.testArray .append(load)
print(self.testArray)
let load2 = object.objectForKey("companydescription") as! String
self.testdecr.append(load2)
print(self.testdecr)
if let userImageFile = object["imagefile"] as? PFFile {
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
self.image = UIImage(data:imageData)!
print("done!")
self.do_table_refresh()
}
}
}
}
}
}
} else {
//log details of failure
print("Error: \(error!) \(error?.userInfo) ")
}
}
// reload UIViewController and UITabkeView
sleep(3)
do_table_refresh()
}
func do_table_refresh () {
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("yourstartups", forIndexPath: indexPath) as! YourStartupsCell
cell.lbTitle!.text = self.testArray[indexPath.row]
cell.lbDescription!.text = self.testdecr[indexPath.row]
cell.logo!.image = self.image
return cell
}
}
I would recommend making an array of PFImage objects, and then in your table view delegate method you can simply access the element at the current row in your index path. Right now your method to get the data is being called once and therefore setting your image to the last fetched object, but since the tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) is being called each time a cell is loaded, you need to keep the images in an array, as you are doing with the text labels.
I am trying to set up a voting system Parse as my backend.
I want to use swipe left and right as the voting method and I am using a query.getObjectInBackgroundWithID so that I can update the vote count to my backend.
I am having trouble querying it and also saving the votes in the back and having that append in to the cell so that the vote count will be added on the tableview cells.
Keep on receiving this error in my log for the query:
no results matched the query (Code: 101, Version: 1.7.2)
How can I correct this? Also How can I make the voting system work after I get the query to work and update the backend?
Here is my code so far:
import UIKit
import Parse
class HomePage: UITableViewController {
let post = PFObject(className: "Post")
var images = [UIImage]()
var titles = [String]()
var imageFile = [PFFile]()
var voteCounter = 0
var count = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
println(PFUser.currentUser())
var query = PFQuery(className:"Post")
query.orderByDescending("createdAt")
query.limit = 15
query.findObjectsInBackgroundWithBlock {(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
println("Successfully retrieved \(objects!.count) scores.")
println(objects!)
if let objects = objects as? [PFObject] {
for object in objects {
if let title = object["Title"] as? String {
self.titles.append(title)
}
if let imgFile = object["imageFile"] as? PFFile {
self.imageFile.append(imgFile)
}
if let voteCounter = object["count"] as? Int {
self.count.append(voteCounter)
}
self.tableView.reloadData()
}
} else {
// Log details of the failure
println(error)
}
}
}
}
/* println("Successfully retrieved \(objects!.count) scores.")
for object in objects! {
self.titles.append(object["Title"] as! String)
self.imageFile.append(object["imageFile"] as! PFFile)
self.tableView.reloadData()
}*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 500
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var myCell:cell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as! cell
myCell.rank.text = "21"
myCell.votes.text = "\(count)"
myCell.postDescription.text = titles[indexPath.row]
imageFile[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
myCell.postedImage.userInteractionEnabled = true;
myCell.postedImage.addGestureRecognizer(swipeRight)
var swipeLeft = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Left
myCell.postedImage.userInteractionEnabled = true;
myCell.postedImage.addGestureRecognizer(swipeLeft)
This is the query that I get errors on:
var query = PFQuery(className:"Post")
query.getObjectInBackgroundWithId("count") {
(Post: PFObject?, error: NSError?) -> Void in
if error != nil {
println(error)
} else if let Post = Post {
Post["count"] = self.voteCounter
Post.saveInBackground()
}
}
return myCell
}
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
voteCounter += 1
println("Swiped right")
case UISwipeGestureRecognizerDirection.Left:
voteCounter -= 1
println("Swiped Left")
default:
break
}
}
}
}
Also here is my Parse backend:
ive added the new code now
import UIKit
import Parse
class HomePage: UITableViewController {
let post = PFObject(className: "Post")
var images = [UIImage]()
var titles = [String]()
var imageFile = [PFFile]()
var votingObjects: [PFObject] = []
override func viewDidLoad() {
super.viewDidLoad()
println(PFUser.currentUser())
println(PFUser.currentUser())
var query = PFQuery(className:"Post")
query.orderByDescending("createdAt")
query.limit = 15
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
println("Successfully retrieved \(objects!.count) scores.")
println(objects!)
for objectRaw in objects! {
let object = objectRaw as! PFObject
self.votingObjects.append(object)
// Adding them to the array
if let title = object["Title"] as? String {
self.titles.append(title)
}
if let imgFile = object["imageFile"] as? PFFile {
self.imageFile.append(imgFile)
}
}
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
// Updating the tableView on the main thread - important. Do some research on Grand Central Dispatch :)
})
} else {
println(error)
// Error
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 500
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var myCell:cell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as! cell
myCell.rank.text = "21"
i cant figure out whats the right code here for the myCell.votes.text to =
myCell.votes.text = votingObjects[indexPath.row]["count"] as? String
myCell.postDescription.text = titles[indexPath.row]
imageFile[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
myCell.postedImage.userInteractionEnabled = true;
myCell.postedImage.addGestureRecognizer(swipeRight)
var swipeLeft = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Left
myCell.postedImage.userInteractionEnabled = true;
myCell.postedImage.addGestureRecognizer(swipeLeft)
return myCell
}
having an issue here:
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
updateVote(true, objectId: String())
println("Swiped right")
case UISwipeGestureRecognizerDirection.Left:
updateVote(false, objectId: String())
println("Swiped Left")
default:
break
}
}
}
func updateVote(increment: Bool, objectId : String) {
// Create a pointer to an object of class Posts with id 'objectId'
var object = PFObject(withoutDataWithClassName: "Post", objectId: objectId)
// Increment the current value of the quantity key by 1
if increment == true {
object.incrementKey("count", byAmount: 1)
} else {
object.incrementKey("count", byAmount: -1)
}
// Save
object.saveInBackgroundWithBlock(nil)
}
}
but i keep recieving the error of cannot update without specific objectId whenever i swipe and initiate the gesture recognizer. i also cant figure out how to display the votes in my cell
It looks like you are querying the Parse db for an objectID which doesn't exist. This is because when you receive the objects, the attribute "count" is the number of votes right... but when you query for an object, you are using "count" as the objectID which obviously won't work. Your idea of using the variable count will also not work.
What I would recommend is a slight adjustment in your structures.
When receiving the objects from the initial query, store them in an array of Parse Objects. This way, you retain all of their information and it will be much easier to update them. The will also provide an attribute object.objectId which is a String, which is what you will need when querying the db again.
Another tip is Parse supports an increment function when dealing with a column of type number
Also, when working on background threads, you should make any UI calls on the main thread using GCD.
Code:
Initial query -
var votingObjects: [PFObject] = []
override func viewDidLoad() {
super.viewDidLoad()
println(PFUser.currentUser())
var query = PFQuery(className:"Post")
query.orderByDescending("createdAt")
query.limit = 15
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
println("Successfully retrieved \(objects!.count) scores.")
println(objects!)
for objectRaw in objects {
let object = objectRaw as! PFObject
self.votingObjects.append(object) // Adding them to the array
}
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData() // Updating the tableView on the main thread - important. Do some research on Grand Central Dispatch :)
})
} else {
// Error
}
}
}
// Pass true if you want to upvote or false if downvote
func updateVote(increment: Bool, objectId : String) {
// Create a pointer to an object of class Posts with id 'objectId'
var object = PFObject(withoutDataWithClassName: "Posts", objectId: objectId)
// Increment the current value of the quantity key by 1
if increment == true {
object.incrementKey("count", byAmount: 1)
} else {
object.incrementKey("count", byAmount: -1)
}
// Save
object.saveInBackgroundWithBlock(nil)
}
}
Your tableView functions will all link to the array now..
numberOfRows will simply use votingObjects.count
TitleForRow will use votingObject[indexPath.row]["Title"]! // Should be 'title'
And any time you want to refer to a voting objects ID, you simply use votingObject[index].objectId
Hope I didn't miss anything :)
I am making an app that has a tableview of images and can be upvoted or downvoted by swiping right or left. Im trying to have the votes be logged in to parse on the backend meanwhile i want the votes to appear in each cell. i have added a voteCounter to count the votes but instead of it being for the specific image it shows the same count on every image. How can i stop this and make it that each image has its own vote and how can i save it to the backend of parse?
heres my code so far:
class HomePage: UITableViewController {
var images = [UIImage]()
var titles = [String]()
var imageFile = [PFFile]()
var voteCounter = 0
override func viewDidLoad() {
super.viewDidLoad()
println(PFUser.currentUser())
var query = PFQuery(className:"Post")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
println("Successfully retrieved \(objects!.count) scores.")
for object in objects! {
self.titles.append(object["Title"] as! String)
self.imageFile.append(object["imageFile"] as! PFFile)
self.tableView.reloadData()
}
} else {
// Log details of the failure
println(error)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 500
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var myCell:cell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as! cell
myCell.rank.text = "21"
myCell.votes.text = "\(voteCounter)"
myCell.postDescription.text = titles[indexPath.row]
imageFile[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Right
myCell.postedImage.userInteractionEnabled = true;
myCell.postedImage.addGestureRecognizer(swipeRight)
var swipeLeft = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
swipeRight.direction = UISwipeGestureRecognizerDirection.Left
myCell.postedImage.userInteractionEnabled = true;
myCell.postedImage.addGestureRecognizer(swipeLeft)
return myCell
}
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
voteCounter += 1
println("Swiped right")
case UISwipeGestureRecognizerDirection.Left:
voteCounter -= 1
println("Swiped Left")
default:
break
}
}
}
}
Don't use all the different arrays, just keep the array of PFObjects and use them directly. This object should also have the vote count as one of its columns so that when you download you get the count. So you also don't need your vote counter.
You should also look at using PFImageView To display the image. Either that or actually cache the downloaded images yourself.
To update the vote count you should use the increment feature offered by PFObject.
First of all, you work with different pictures, for my part I prefer working with a single table for the tableView.
Every element of your table will correspond to a line of TableView like this :
NOTE : You will have to rearrange the code as you wish
class HomePage: UITableViewController {
var dataTab : [FPObject] : []
override func viewDidLoad() {
super.viewDidLoad()
//Init your data array for tableView
println(PFUser.currentUser())
var query = PFQuery(className:"Post")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
println("Successfully retrieved \(objects!.count) scores.")
for object in objects! {
self.dataTab.append(object)
self.tableView.reloadData()
}
} else {
// Log details of the failure
println(error)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataTab.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 500
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Get Object at IndexPath.row in dataArray for tableView
let rowObject = self.dataTab[indexPath.row]
let rank = rowObject["rank"]
let votes = rowObject["votes"]
let description = rowObject["Title"]
myCell.rank.text = rank
myCell.votes.text = votes
myCell.postDescription.text = description
//Asynchrone task
rowObject["imageFile"].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
//When download success -- reload tableview to update cells
myCell.postedImage.image = downloadedImage
self.tableView.reloadData()
}
}
return myCell
}
//ACTION WHEN EDIT CELL TABLEVIEW -- Look differents screens
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
var upAction = UITableViewRowAction(style: .Default, title: "UP") { (action, indexPath) -> Void in
//Get object at index
let updateObject = self.dataTab[indexPath.row]
//Update data tableview // Increment vote
self.dataTab[indexPath.row]["vote"] = updateObject["vote"] + 1
//UPDATE data in Parse.com
let objectId = updateObject["objectId"]
var query = PFQuery(className:"Post")
query.getObjectInBackgroundWithId(objectId) {
(postObject: PFObject?, error: NSError?) -> Void in
if error != nil {
println(error)
} else if let postObject = postObject {
postObject["vote"] = postObject["vote"] + 1
postObject.saveInBackground()
}
}
//Reload tableview cells
self.tableView.reloadData()
}
upAction.backgroundColor = UIColor.greenColor()
var downAction = UITableViewRowAction(style: .Default, title: "DOWN") { (action, indexPath) -> Void in
//Get object at index
let updateObject = self.dataTab[indexPath.row]
//Update data tableview // Increment vote
self.dataTab[indexPath.row]["vote"] = updateObject["vote"] - 1
//UPDATE data in Parse.com
let objectId = updateObject["objectId"]
var query = PFQuery(className:"Post")
query.getObjectInBackgroundWithId(objectId) {
(postObject: PFObject?, error: NSError?) -> Void in
if error != nil {
println(error)
} else if let postObject = postObject {
postObject["vote"] = postObject["vote"] - 1
postObject.saveInBackground()
}
}
//Reload tableview cells
self.tableView.reloadData()
}
return [upAction, downAction,]
}
}
screen result to upvote and downvote if you want to use this
I hope I have helped you
Ysée