I am stuck for a very long time. I am trying to implement a vote feature in a collection view. If the user taps the button it adds one vote to parse and shows it on the label. My code does that however when I look into the parse dashboard I see that a new row is create and the number of votes is not going into the post
My code for the cell is
import UIKit
import ParseUI
import Parse
var votes = [PFObject]()
class NewCollectionViewCell: UICollectionViewCell {
var parseObject = PFObject(className: "Posts")
#IBOutlet weak var postsImageView: PFImageView!
#IBOutlet weak var postsLabel: UILabel!
#IBOutlet weak var votesLabel:UILabel?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
postsLabel.textAlignment = NSTextAlignment.Center
print("Passing11")
}
#IBAction func vote(sender: AnyObject) {
if let votes = parseObject.objectForKey("votes") as? Int {
parseObject.setObject(votes + 1, forKey: "votes")
parseObject.saveInBackgroundWithTarget(nil, selector: nil)
votesLabel?.text = "\(votes + 1) votes"
print("Passing22")
}
else
{
parseObject.setObject(1, forKey: "votes")
parseObject.saveInBackgroundWithTarget(nil, selector: nil)
votesLabel?.text = "1 votes"
print("Passing33")
}
}}
and collection view is
if let votes = parseObject.objectForKey("votes") as? Int {
cell.votesLabel?.text = "\(votes) votes"
}
else
{
cell.votesLabel?.text = "0 votes"
}
return cell
}
How can I make it work? Thank you.
From what I remember in my Parse project. If you need to retrieve and update an existing row in Parse you need to create a PFQuery object first and retrieve the desired row using that query object. And then you can update its "vote" or whatever attribute value you want to. Kindly try that.
Related
How can I not repeat the array when I click on the button in swift? I'm trying to generate fruits without them repeating.
import UIKit
class fruitrandomViewController: UIViewController {
#IBOutlet weak var nextfruitButton: UIButton!
#IBOutlet weak var fruitbox: UILabel!
#IBAction func fruitbutton(_ sender: UIButton) {
let array = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear",]
let randomFruitgenerator = Int(arc4random_uniform(UInt32(array.count)))
fruitbox.text = array[randomFruitgenerator]
}
}
My suggestion is to use a Set and remove the random item from the set
var set = Set(["Apple","Banana","Orange","Pinapple", "Plum", "Pear"])
#IBAction func fruitbutton(_ sender: UIButton) {
if let fruit = set.randomElement() {
fruitbox.text = fruit
set.remove(fruit)
} else {
fruitbox.text = "" // or whatever to indicate that the set is empty
}
}
My suggest:
You can random each item 1 time
let originFruits = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear"]
let array = originFruits
#IBAction func fruitbutton(_ sender: UIButton) {
...
let fruitRandom = array random
array delete fruitRandom
if (array empty) {
array = originFruits
}
}
You can check and remove in next time
let originFruits = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear"]
let array = originFruits
let skipFruit = ""
#IBAction func fruitbutton(_ sender: UIButton) {
...
array = originFruits
array delete skipFruit
let fruitRandom = array random
skipFruit = fruitRandom
}
I think this will work, but I think it's Time Complexity can be O(n) as I am assuming that there is a possibility of randomElement return Apple every time and savedFruit is also Apple, so in that case, the Time Complexity will be O(n). A better workaround will be to remove that element from that array so, the next time the randomElement will be different for sure. Then, once it is different you can append the old one and remove the current one. I hope it makes sense to you, but for now this will work I think:
let array = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear"]
var savedFruit = String()
func fetchRandomFruit() {
if let fruit = array.randomElement() {
if fruit != savedFruit { //Here it will check if the last element is same as the new randomElement
savedFruit = fruit
fruitbox.text = savedFruit
} else {
fetchRandomFruit()
}
}
}
#IBAction func fruitbutton(_ sender: UIButton) {
fetchRandomFruit()
}
Use fruitbox.text = array.randomElement() ?? "default value for if array is empty". This is not guaranteed not to repeat, but is random.
If you want to ensure it does not repeat, use this
var new = array.randomElement() ?? fruitbox.text
while new == fruitbox.text {
new = array.randomElement() ?? fruitbox.text
}
fruitbox.text = new
This WILL loop infinitely (until it crashes) if the array is empty.
I'm trying to load my data into a WatchKit table. Basically, set the text of the match label in each table group cell with the array of matchs I have.
I've got the data, and everything set up, but actually loading it into the table is where I'm stuck.
InterfaceController.swift:
var receivedData = Array<Dictionary<String, String>>()
var eventsListSO = Array<Event>()
#IBOutlet var rowTable: WKInterfaceTable!
func doTable() {
eventsListSO = Event.eventsListFromValues(receivedData)
rowTable.setNumberOfRows(eventsListSO.count, withRowType: "rows")
for var i = 0; i < self.rowTable.numberOfRows; i++ {
let row = rowTable.rowControllerAtIndex(i) as? TableRowController
for eventm in eventsListSO {
row!.mLabel.setText(eventm.eventMatch)
NSLog("SetupTableM: %#", eventm.eventMatch)
}
}
}
I was trying to do it in doTable because that seemed like best place to do this, and I think doTable is set up right, but I'm not sure? Not sure if I need to make the array an optional type or what.
Here is the referencing code if needed:
RowController.swift:
class TableRowController {
#IBOutlet var mLabel: WKInterfaceLabel!
#IBOutlet var cGroup: WKInterfaceGroup!
}
Event.swift:
class Event {
var eventTColor:String
var eventMatch:String
init(dataDictionary:Dictionary<String,String>) {
eventTColor = dataDictionary["TColor"]!
eventMatch = dataDictionary["Match"]!
}
class func newEvent(dataDictionary:Dictionary<String,String>) -> Event {
return Event(dataDictionary: dataDictionary)
}
class func eventsListFromValues(values: Array<Dictionary<String, String>>) -> Array<Event> {
var array = Array<Event>()
for eventValues in values {
let event = Event(dataDictionary: eventValues)
array.append(event)
}
return array
}
}
So I'm not sure if:
- doTable is set up right (can't be because eventsListSO.count is null)
The way you work with tables in WatchKit is a lot different than UIKit.
After you call setNumberOfRows you need to iterate over each row and get the RowController.
for var i = 0; i < self.rowTable.numberOfRows; i++ {
var row = self.rowTable.rowControllerAtIndex(i)
//setup row here
}
You can check Raywenderlich's tutorial about WatchKit: http://www.raywenderlich.com/96741/watchkit-tutorial-with-swift-tables-glances-and-handoff, it teach you how to show tables on your watch, hope this help!
Hello I get an error saying Could not find overload for != that accepts the supplied documents and don't know what to change. I am stuck for a very long time. I am trying to implement a vote feature in a collection view. If the user taps the button it adds one vote to parse and shows it on the label. Is my method wrong? Below is the code for Collection view cell the highlighted code is where the error is.
import UIKit
import ParseUI
import Parse
var votes = [PFObject]()
class NewCollectionViewCell: UICollectionViewCell {
var parseObject = PFObject(className: "Posts")
#IBOutlet weak var postsImageView: PFImageView!
#IBOutlet weak var postsLabel: UILabel!
#IBOutlet weak var votesLabel:UILabel?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
postsLabel.textAlignment = NSTextAlignment.Center
print("Passing11")
}
#IBAction func vote(sender: AnyObject) {
if (parseObject != nil)
{
if let votes = parseObject!.objectForKey("votes") as? Int {
parseObject!.setObject(votes + 1, forKey: "votes")
parseObject!.saveInBackgroundWithTarget(nil, selector: nil)
votesLabel?.text = "\(votes + 1) votes"
print("Passing22")
}
else
{
parseObject!.setObject(1, forKey: "votes")
parseObject!.saveInBackgroundWithTarget(nil, selector: nil)
votesLabel?.text = "1 votes"
print("Passing33")
}
}}}
And I also have an error "use of unresolved identifier parse objects"
if (parseObject != nil)
{
if let votes = parseObject!.objectForKey("votes") as? Int {
cell.votesLabel?.text = "\(votes) votes"
}
else
{
cell.votesLabel?.text = "0 votes"
}
}
return cell}
Any help is appreciated. Thank you.
This compiler error will appear only if your parseObject is of type PFObject and not PFObject?.
From what I can see through your code:
var parseObject = PFObject(className: "Posts")
The above line states that your parseObject will be of type PFObject and not optional. It will be optional only if your initializer is failable.
So if parseObject is not optional, then there is no need for nil check.
Hope it helps.
Im currently implementing a like functionality in my app, and I can't seem to be able to get this append and retrieving to work. Here is my Button Action which is found in my ViewController file
var Liked = Favourite()
let factBook = FactBook()
#IBAction func favour() {
var currentQuote = factBook.factsArray[factIndex]
Liked.favouriteArray.append(currentQuote)
}
The Favourite struct is called from
import Foundation
struct Favourite {
var favouriteArray: [String] = []
}
(The factBook struct is the same thing except the array actually has elements inside.)
Now my goal is to get all this to display on a separate view controller called favouriteViewController:
import UIKit
class FavouriteViewController: UIViewController {
#IBOutlet var LikeQuote: UILabel!
var liked = Favourite()
override func viewDidLoad() {
super.viewDidLoad()
if liked.favouriteArray.count > 0 {
LikeQuote.text = liked.favouriteArray[0]
} else if liked.favouriteArray.count == 0 {
LikeQuote.text = "No Liked Quotes Found, Go Favour Some!"
}
}
Now when I hit the button, theoretically I should be able to append it to the favouriteArray and then be able to display it on my favouriteViewController file, however when I save it and then open viewcontroller file it defaults to the liked.favouriteArray.count=0 scenario and prints out the text no matter how many quotes I save. I just need an idea of what's going wrong in this process?
Update: If I put append Hello world into text it still does not append to element and evaluates the array value as 0.
The problem is that because you are not saving the data somewhere like into a database or file, you won't be able to retrieve it so the code you add into the viewDidLoad will not work The only way for it to work is when the UIButton was tapped check the code below. Hope that Helps
import Foundation
import UIKit
struct Favourite {
var favouriteArray = [String]()
}
class FavouriteViewController: UIViewController {
// let factBook = FactBook()
#IBOutlet var LikeQuote: UILabel!
var liked = Favourite()
override func viewDidLoad() {
super.viewDidLoad()
}
func updateContent(){
if liked.favouriteArray.count > 0 {
LikeQuote.text = liked.favouriteArray[0]
}
else if liked.favouriteArray.count == 0 {
LikeQuote.text = "No Liked Quotes Found, Go Favour Some!"
}
}
#IBAction func favour() {
// var currentQuote = liked.factsArray[factIndex]
// Liked.favouriteArray.append(currentQuote)
liked.favouriteArray.append("today is a new day ")
updateContent()
}
}
I have a table view in my Chat app that holds Users that are logged in to the application. This app is in Swift and the table view is embedded in a Navigation controller. I'm also using Parse.
When I click on a User, it sends me to a chat screen which it's suppose to do. Then when I click the Back button, it takes me back to the User table view as it should, but something strange happens. It has the Users that are logged in, but shows them twice. For example, If User1 is logged in to the app, I click on it to chat, then go back to the table view, it now shows User1 twice. If I repeat the process, it then shows User1 three times. Hopefully someone can help...
Variables:
import UIKit
// Global Variable
var userName = ""
class usersVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var resultsTable: UITableView!
var resultsUsernameArray = [String]()
var resultsProfileNameArray = [String]()
var resultsImageFile = [PFFile]()
override func viewDidLoad() {
super.viewDidLoad()
let theWidth = view.frame.size.width
let theHeight = view.frame.size.height
resultsTable.frame = CGRectMake(0, 0, theWidth, theHeight-64)
// PFUser.currentUser().username is part of Parse framework
userName = PFUser.currentUser()!.username!
}
Then here is the viewDidAppear where I believe is the issue:
override func viewDidAppear(animated: Bool) {
let predicate = NSPredicate(format: "username != '"+userName+"'")
var query = PFQuery(className: "_User", predicate: predicate)
var theObjects = query.findObjects()
for object in theObjects! {
// object.username is the name of the username class in Parse, as well as "profileName" and "photo"
self.resultsUsernameArray.append(object["username"] as! String)
self.resultsProfileNameArray.append(object["profileName"] as! String)
self.resultsImageFile.append(object["photo"] as! PFFile)
self.resultsTable.reloadData()
}
}
Not sure if this is needed but it had some of the same variables and deals with the Table View:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : ResultsCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ResultsCell
cell.usernameLbl.text = self.resultsUsernameArray[indexPath.row]
cell.usernameLbl.hidden = true
cell.profileNameLbl.text = self.resultsProfileNameArray[indexPath.row]
resultsImageFile[indexPath.row].getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.profileImg.image = image
}
}
return cell
}
Let me know if more code is needed!
Thank you,
Jack
You should change your viewDIdAppear() method little bit way like this,
override func viewDidAppear(animated: Bool) {
let predicate = NSPredicate(format: "username != '"+userName+"'")
var query = PFQuery(className: "_User", predicate: predicate)
var theObjects = query.findObjects()
self.resultsUsernameArray.removeAll(keepCapacity: true)
self.resultsProfileNameArray.removeAll(keepCapacity: true)
self.resultsImageFile.removeAll(keepCapacity: true)
for object in theObjects! {
// object.username is the name of the username class in Parse, as well as "profileName" and "photo"
self.resultsUsernameArray.append(object["username"] as! String)
self.resultsProfileNameArray.append(object["profileName"] as! String)
self.resultsImageFile.append(object["photo"] as! PFFile)
self.resultsTable.reloadData()
}
}
HTH, Enjoy Coding !!