Re-accessing random data between methods in ViewController - ios

For my Swift app, I want the data accessed in the didReceiveMemoryWarning function to be from the same random column of data retrieved from the viewDidLoad function, which was done with let randNumber = Int(arc4random_uniform(UInt32(count))). My app is a poll app where users can vote for different poll options then when they click the "Next" button, it takes them to another poll at random. The code under the didReceiveMemoryWarning function is for adding the vote (and retrieving it) from a poll, but I need that poll to be the same one displayed by the viewDidLoad function. How do I do that? For some reason no matter what poll I retrieve (crepes or pancakes, Coke or Pepsi, chocolate or vanilla, etc.) it only adds votes to and retrieves the results from the "crepes or pancakes" poll. Like if the user gets the poll "Coke or Pepsi" and they select Coke, it'll add a vote to the crepes vote count and retrieve the results from that poll. How do I retrieve data from the poll that is retrieved?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var query = PFQuery(className: "VoteCount")
query.countObjectsInBackgroundWithBlock {
(count: Int32, error: NSError!) -> Void in
if error == nil {
let randNumber = Int(arc4random_uniform(UInt32(count)))
query.whereKey("pollNumber", equalTo: randNumber)
query.getFirstObjectInBackgroundWithBlock {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
let option1 = voteCount1["optionName"] as String
let option2 = voteCount1["optionName2"] as String
self.showOption1.text = "\(option1)"
self.showOption2.text = "\(option2)"
}
}
} else {
println("error \(error)")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var pollResults: UILabel!
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
var query = PFQuery(className: "VoteCount")
query.getFirstObjectInBackgroundWithBlock {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
voteCount1.incrementKey("votes")
voteCount1.saveInBackgroundWithTarget(nil, selector: nil)
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
self.pollResults.text = "\(votes) \(votes2)"
}
}
}

You could make randomNumber a property instead of a local variable. However I think what you're actually trying to do is make sure you access the same PFObject in your later methods as you do in viewDidLoad. To do this, you don't need to re-fetch from Parse. Just keep a reference to the PFObject:
var voteCount : PFObject?
And in your completion block in viewDidLoad:
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
self.voteCount = voteCount1
// The rest of your code...
let votes = voteCount1["votes"] as Int
Then, later on, instead of fetching again, you just use the voteCount property:
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
voteCount.incrementKey("votes")
voteCount.saveInBackgroundWithTarget(nil, selector: nil)
let votes = voteCount["votes"] as Int
let votes2 = voteCount["votes2"] as Int
self.pollResults.text = "\(votes) \(votes2)"
}

Related

Delete a row from a class in Parse - In Swift

I'm trying to make some voting buttons for my film app.
I use Parse, and I've created a new class called Votes_Up. In this class their are 2 columns: User_Voting and Film_VotedFor.
My code below is actioned when the button is pressed. It takes the currentUser and the film object that the button has been pressed against, and adds them to Parse. My database looks like this:
What I need
so they way it currently works, if the user presses the vote button, it adds the info to the DB and adds 1 to the count. When the user presses it again, it just updates the count by taking 1 away.
I would also want to remove the row it would have added to the database, By the User that voted for it. How can I do this??
My code:
#IBAction func upVoteButton(sender: UIButton) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
if PFUser.currentUser() != nil {
if userPressedUpButton == false {
userPressedUpButton = true
let voteUp = PFObject(className: "Votes_Up")
voteUp["User_Voting"] = PFUser.currentUser()
voteUp["Film_VotedFor"] = object!
object!.incrementKey("UpVoteCount")
object!.saveInBackground()
voteUp.saveInBackgroundWithBlock({ (success, error) in
if success == true {
// Object(s) was/were successfully saved
} else if error != nil {
// Display an alert to the user
} else {
// Display an alert to the user - something went wrong
}
})
} else {
userPressedUpButton = false
// I need to removed the row from the class here that was added, as the user has retracted their vote!
object!.incrementKey("UpVoteCount", byAmount: -1)
object!.saveInBackground()
}
} else {
// No user is logged in so they can't vote
performSegueWithIdentifier("Votes_LoginPopup", sender: self)
}
self.tableView.reloadData()
}
Try this:
var query = PFQuery(className:"Votes_Up")
query.whereKey("User_Voting", equalTo:PFUser.currentUser())
query.limit = 1
query.findObjectsInBackgroundWithBlock {
(votesUp: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = votesUp as? [PFObject] {
var firstObject = objects[0]
dispatch_async(dispatch_get_main_queue(),{
// do delete here
firstObject.deleteEventually();
})
}
}
}
or this:
let query = PFQuery(className: "Votes_Up")
query.whereKey("User_Voting", equalTo: PFUser.currentUser())
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects {
object.deleteEventually()
}
}

How to create an array of usersnames when working with Parse and Swift

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

Swift& Parse.com Adding values from a table into an array error not having a member named subscript

I have a table called Assesment
it has the name and send values of each task
what I needed to do is to retrieve all these tasks and store them in an array
and here is my code which gives me an error saying that PFObject doesn't have a member called send:
override func viewDidLoad() {
super.viewDidLoad()
//test
var taskQuery = PFQuery(className: "Assesment")
//run query
taskQuery.findObjectsInBackgroundWithBlock({
(success:[AnyObject]?, error: NSError?) -> Void in
if (success != nil) {
for object:PFObject! in success as! [PFObject]{
ERROR>>>> taskMgr.addtask(object.name,send: object.name)
}
println(taskMgr)
}})
//test
// Do any additional setup after loading the view, typically from a nib.
}
even thought I tried to say instead
taskMgr.addtask(object)
AssesmentManager.swift class:
import UIKit
var taskMgr : AssesmentsManager = AssesmentsManager()
struct task {
var name = "Un-Named"
var send = false
}
class AssesmentsManager: NSObject {
var tasks = [task]()
func addtask(name: String, send: Bool) {
tasks.append(task(name: name, send: send))
}
}
UPDATE
if (success != nil) {
for object:PFObject! in success as! [PFObject]{
if object["send"]=="true"{
taskMgr.addtask(object["name"], true )
}
else{
taskMgr.addtask(object["name"], false )}
}
I updated it to remove the string, boolean problem but I still have the same error of not having a member named subscript
UPDATE#2
This is what it looks like now, but still giving me an error that objects is unresolved:
var taskQuery = PFQuery(className: "Assesment")
//run query
taskQuery.findObjectsInBackgroundWithBlock({
(success:[AnyObject]?, error: NSError?) -> Void in
if (success != nil) {
for object:PFObject! in success as! [PFObject]{
for object in objects {
taskMgr.addtask(object["name"], (object["send"] == "true"))
}
}
println(taskMgr)
}})
In Swift 2.0, findObjects returns optional array of PFObject instead of optional AnyObject. Try this
override func viewDidLoad() {
super.viewDidLoad()
var taskQuery = PFQuery(className: "Assesment")
taskQuery.findObjectsInBackgroundWithBlock {
(success:[PFObject]?, error: NSError?) -> Void in
if let objects = success {
for object in objects {
taskMgr.addtask(object["name"], (object["send"] == "true"))
//taskMgr.addtask(object["name"], (object["send"].isEqual("true")))
}
}
}
}

Passing objectId from viewDidLoad to another function using Parse method getObjectInBackgroundWithId not working

I'm a beginner working with Parse and Swift. I need to update the object referred to in my viewDidLoad in another function within the same controller. How do I pass the currently loaded object's objectId without having to hardcode it like this:
query.getObjectInBackgroundWithId("8DkYgraEJq")
Here is my viewDidLoad function:
override func viewDidLoad() {
var query = PFQuery(className: "CheckedBaggage")
query.orderByAscending("createdAt")
query.whereKey("respondedTo", notEqualTo: true)
query.getFirstObjectInBackgroundWithBlock {
(CheckedBaggage: PFObject!, error: NSError!) -> Void in
if error != nil {
println("The getFirstObject request failed.")
} else {
// The find succeeded.
self.randomBaggageLabel.text = CheckedBaggage.objectForKey("message") as? NSString
CheckedBaggage.save()
println(CheckedBaggage.objectId)
let baggageId = CheckedBaggage.objectId
println("Successfully retrieved the object.")
}
}
I would like to try and pass the variable baggageId, which should be the object's ID as a string, as an argument to the getObjectInBackgroundWithId block in my carryIt function:
#IBAction func carryIt(sender: AnyObject!) {
println("CarryIt is being called")
var query = PFQuery(className: "CheckedBaggage")
query.getObjectInBackgroundWithId(baggageId) {
(CheckedBaggage: PFObject?, error: NSError?) -> Void in
if error != nil {
println(error)
} else if let CheckedBaggage = CheckedBaggage {
println("object hello!")
CheckedBaggage["respondedTo"] = true
CheckedBaggage["response"] = self.kindnessMessage.text
CheckedBaggage.save()
}
}
}
But I'm getting an "unresolved identifier" error. It updates my Parse database perfectly fine if I hardcode the object ID, but I can't do it this way. Here's a screenshot of the error:
Thank you so much for your help!
You have to initialize baggageId. To use it in multiple functions, it must be scoped at class level as the comment said. To set it after it has been declared, it must be a "var", not a constant "let".
var baggageId = ""
func viewDidload() {
var query = ...
query.get... {
baggageId = CheckedBaggege.objectId
}
}
func shipIt() {
var query = ...
query.getObjectWithId(baggageId) ...
}

Calling values from a random row in Parse?

I'm trying to figure out how to call values from all columns for each variable within a random row, and each row is denoted by its own specific objectId, which is the name of the column, on Parse. Here is where I've defined the values of the variables in each column:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var voteCount1 = PFObject(className: "VoteCount")
voteCount1["choices"] = 2
voteCount1["votes"] = Int()
voteCount1["votes2"] = Int()
voteCount1["optionName"] = String()
voteCount1["optionName2"] = String()
}
I've figured out how to make it so that a button will send a vote to a variable's vote count (defined as an Int) in the row of a specific object ID, but I don't know how to call polls from a random Object ID and send votes to the corresponding choices in that row. Here's my IBAction of adding votes to a variable of a specific object ID:
#IBAction func addVote1(sender: AnyObject) {
for button in self.buttons {
button.enabled = false
}
var query = PFQuery(className: "VoteCount")
query.getObjectInBackgroundWithId("BiEM17uUYT") {
(voteCount1: PFObject!, error: NSError!) ->Void in
if error != nil {
NSLog("%#", error)
} else {
voteCount1.incrementKey("votes")
voteCount1.saveInBackgroundWithTarget(nil, selector: nil)
}
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
let percent1 = votes * 100 / (votes + votes2)
let percent2 = votes2 * 100 / (votes + votes2)
self.pollResults1.text = "\(percent1)% (\(votes)) \(percent2)% (\(votes2))"
}
}
How do I call values from random rows?
UPDATE: I just tried the following re-written from objective-C but I'm not sure if it's right:
var query = PFQuery(className: "VoteCount")
query.findObjectsInBackgroundWithBlock {
(objects: NSArray, error: NSError!) -> Void in
if error == nil {
randNumber = arc4random_uniform(count)
query2.whereKey("voteNumber", equalTo:randNumber)
query2.getFirstObjectInBackgroundWithBlock {
(voteCount1: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
let votes = voteCount1["votes"] as Int
let votes2 = voteCount1["votes2"] as Int
let option1 = voteCount1["optionName"] as String
let option2 = voteCount1["optionName2"] as String
self.showOption1.text = "\(option1)"
self.showOption2.text = "\(option2)"
}
}
}
You would never hard-code object ids in your code. In order to fetch a random row, simply fetch all of the rows from Parse and then select one at random.
For example
PFQuery *query = [PFQuery queryWithClassName:#"VoteCount"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
NSInteger index=arc4random_uniform(objects.count);
NSLog("The random object is %#",objects[index]);
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
For a more useful implementation you would probably store the objects array into a property so that you could refer to it from outside the block.
Note that by default, only the first 100 rows will be returned. You can increase the limit up to 1000. Beyond 1000 you have to use paging with multiple queries. See https://parse.com/questions/fetch-all-data-in-a-table-using-pfquery
var query = PFQuery(className: "VoteCount")
query.findObjectsInBackgroundWithBlock {
(objects: NSArray, error: NSError!) -> Void in
if error == nil {
if let randomObject=objects[arc4random_uniform(objects.count)] {
println("The random object is \(randomObject)\")
}
} else {
println("error \(error)")
}
}

Resources