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 :)
Related
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
}
}
}
I've been working on it from 2 weeks now, I've Instagram like app, where user can signUp and Login using Parse backend. Now after signUp a segue is made for the next screen called userListTableViewController here users will be allowed to follow the already existing users. Now i trying to retrieve data in NSMutableArray and show them as follows:
import UIKit
class userListTableViewController: UITableViewController {
var data:NSMutableArray = NSMutableArray()
var isFollowing = [PFObject:Bool]()
func loadData() {
data.removeAllObjects()
isFollowing.removeAll(keepCapacity: true)
var userQuery = PFUser.query()
userQuery?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error != nil {
} else {
if let objects = objects {
for object in objects {
if let user = object as? PFObject {
if user.objectId != PFUser.currentUser()?.objectId {
self.data.addObject(user)
var followerQuery: PFQuery = PFQuery(className: "Followers")
followerQuery.whereKey("follower", equalTo: PFUser.currentUser()!)
followerQuery.whereKey("user", equalTo: user)
followerQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
if objects.count > 0 {
self.isFollowing[user] = true
} else {
self.isFollowing[user] = false
}
}
if self.isFollowing.count == self.data.count {
self.tableView.reloadData()
}
})
}
}
}
}
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
/*
var array:NSMutableArray = NSMutableArray(array: self.data.reverseObjectEnumerator().allObjects)
self.data = array as NSMutableArray
self.tableView.reloadData()
*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return data.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("users", forIndexPath: indexPath) as! userListTableViewCell
let userData:PFObject = self.data.objectAtIndex(indexPath.row) as! PFObject
myCell.fullName.text = userData["objectId"] as! String!
myCell.genderLabel.text = userData["gender"] as! String!
// var array:NSMutableArray = NSMutableArray(array: self.data.reverseObjectEnumerator().allObjects)
// self.data = array as NSMutableArray
let followedId = // What should i use here?? *****************
if isFollowing[followedId] == true { // ERROR!! not able to use followedId here.. how should i give a value so that it will check the particular user's objectId and isFollowing Bool value. ******************
myCell.followButtton.setTitle("unfollow", forState: UIControlState.Normal)
} else {
myCell.followButtton.setTitle("follow", forState: UIControlState.Normal)
}
userData["profilePicture"]?.getDataInBackgroundWithBlock({ (data, error) -> Void in
if let downloadeImage = UIImage(data: data!) {
myCell.dp.image = downloadeImage
}
myCell.followButtton.tag = indexPath.row
myCell.followButtton.addTarget(self, action: "followButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
})
return myCell
}
// IBActions..
func followButtonTapped(sender: UIButton){
let userData:PFObject = self.data.objectAtIndex(sender.tag) as! PFObject
let followedId = userData["objectId"] as! PFObject
if isFollowing[followedId] == false {
isFollowing[followedId] = true
sender.setTitle("unfollow", forState: UIControlState.Normal)
let getObjectByIdQuery = PFUser.query()
getObjectByIdQuery?.whereKey("objectId", equalTo: userData.objectId!)
getObjectByIdQuery?.getFirstObjectInBackgroundWithBlock({ (foundObject:PFObject?, error:NSError?) -> Void in
if let object = foundObject {
var followers:PFObject = PFObject(className: "Followers")
followers["user"] = object
followers["follower"] = PFUser.currentUser()
followers.saveInBackgroundWithBlock({ (success, error) -> Void in
if error != nil {
println(error)
} else {
println("saved")
}
})
}
})
} else {
isFollowing[followedId] = false
sender.setTitle("follow", forState: UIControlState.Normal)
var query:PFQuery = PFQuery(className: "Followers")
query.whereKey("follower", equalTo: PFUser.currentUser()!)
query.whereKey("user", equalTo: data[sender.tag])
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
object.deleteInBackgroundWithBlock({ (success, error) -> Void in
if error != nil {
println(error)
} else {
println("deleted")
}
})
}
}
})
}
}
}
shown the problem in the code as comment.. or else can you please suggest me some other way better than this.. i've tried to retrieve data in arrays also, there also i'm getting problem for the "follow" buttons. You can see the problem here.. Not able to reload data properly when retrieving objects from Parse .. Please check this link too..
Please help me out here.. Thanks..
Edit: I just want to make the user list with there gender full name and profile picture, and want to allow user to follow them with a button "follow" on each cell.. and if the app restarts, the users which have been already followed by the current user must be marked as "unfollow" to unfollow the user if current user wants it..
check the comments in the code.. error is there where you see "***************" it's in cellForRowAtIndexPath
Instead of playing with PFUser, arrays and dictionaries, create a class User in application side.
class User: NSObject {
var pfUser : PFObject?
var isFollowing : Bool = false
}
And in loadData method,
func loadData() {
// **************** Your Codes ********************
if user.objectId != PFUser.currentUser()?.objectId {
var otherUser = User()
otherUser.pfUser = user
// **************** Your Codes ********************
followerQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
if objects.count > 0 {
otherUser.isFollowing = true
}
}
})
self.data.addObject(otherUser)
}
}
Then use the single mutableArray data to populate tableView.
I have been trying to create a voting system so I can log the votes a certain image gets and display them in a cell.
I can't seem to get my voting to work properly I'm currently trying to use the += and -= operands because I couldn't figure out the increment count, but I keep getting an error message on post.count += or -= 1 of : PFObject does not have a member named count which I do in my parse backend:
Here is my code that i have so far:
import UIKit
import Parse
class HomePage: UITableViewController {
let post = PFObject(className: "Post")
var images = [UIImage]()
var titles = [String]()
var imageFile = [PFFile]()
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)
return myCell
}
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
post.count += 1
println("Swiped right")
case UISwipeGestureRecognizerDirection.Left:
post.count -= 1
println("Swiped Left")
default:
break
}
}
}
}
How can I make the count work in this code? Why do I keep getting that error and how can I log the count for each specific image?
any type of voting system code would be appreciated i can change it up i just want to keep the swipe gesture as the way you upvote and downvote.
Your table has a number of lines (at least four) that don't have any "count" parameters. Delete them, or change your code to do this:
var potentialVoteCounter : Int? = object["count"]
if potentialVoteCounter == nil {
// create "count" in this Parse object
let zero:NSNumber = 0
object["count"] = zero
}
if let voteCounter = object["count"] as? Int {
self.count.append(voteCounter)
}
or
if let voteCounter = object["count"] as? Int {
// do nothing here...
} else {
// create "count" in this object
let zero:NSNumber = 0
object["count"] = zero;
}
if let voteCounter = object["count"] as? Int {
self.count.append(voteCounter)
}
making certain to save your updated Parse object at the end (so the table will reflect changes that you made)
I am trying to create a voting system and store it to my backend and have it come up for each individual picture and be stored for each picture. I created a column in my backend Parse called "count" but i cant seem to get the votes to be brought up or saved in the back and added. I am using a swipeGestureRecognizer to initiate the voting right for one up left for one down but i cant get the correct syntax at the switch statement for the -= and += and i get the error of Binary operator '+='/'-=' cannot be applied to operands of type '[(Int)]' and 'Int'what can i do to make the voting system work to both save in the backend and be brought up and shown each individual pics votes?
import UIKit
import Parse
class HomePage: UITableViewController {
var images = [UIImage]()
var titles = [String]()
var imageFile = [PFFile]()
var count = [Int]()
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.")
println(objects!)
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)
return myCell
}
func respondToSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.Right:
count += 1
println("Swiped right")
case UISwipeGestureRecognizerDirection.Left:
count -= 1
println("Swiped Left")
default:
break
}
}
}
}
this is what i have now but the voting still wont get logged into parse and the post.count += 1 and post.count-=1 is receiving error messages of 'PFObject' does not have a member named 'count' where am i going wrong?
First of all, what you display on screen should depend entirely on your Parse model. What I mean is - you increment a count property every time a user votes. What will happen if the user stays in this screen for an hour and by that time 10 more users also vote? This won't be updated in the current screen and the user will see votes that are not up to date.
So what you can do is to create an object which inherits from PFObject. This object will be tied to Parse and will be always up to date.
What you can start with is reading the documentation. This can help you too.
So the main idea is to have your Parse columns as properties of a PFObject subclass:
class Post: PFObject, PFSubclassing {
#NSManaged var count: Int
class func parseClassName() -> String! {
return "Post"
}
}
In your AppDelegate's application(_:didFinishLaunchingWithOptions:) method register your Parse class like this:
Post.registerSubclass()
When you want to change the count property you'll have to set it and then update the screen:
let post = PFObject(className: "Post")
//increment like this
post.count += 1
//decrement like this
post.count -= 1
//refresh screen
//call reloadData()
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