How to populate a TableView with data from Firebase Firestore? - ios

I am very new to iOS development (with emphasis on very). I think I have grasped simple table views in Xcode without calling on a database, and I also think I understand the basics of how to call data from Firestore, but I cannot for the life of me figure out how to populate my TableView with data from Firestore.
The Firestore collection I want to populate with is called "articles", where each doc represents an article I want to display in a cell. Each doc has this structure of data:
imageURL: https://someurl.com
title: 5 places you don't want to miss
I have created a UITableView with a UITableViewCell inside it in Storyboard, where the TableViewCell's ContentView contains an ImageView for the 'imageURL' data in Firestore and a Label for the 'title' data in Firetore.
The UITableView in Storyboard is linked to ArtiklerTableViewController.swift.
Likewise is the UITableViewCell linked to ArtiklerCell.swift.
The two Swift files look like this now:
ArtiklerTableViewController.swift
class ArtiklerTableViewController: UITableViewController {
#IBOutlet var artiklerTableView: UITableView!
var artiklerArray: [String] = []
var documents: [DocumentSnapshot] = []
var db: Firestore!
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
configureTableView()
loadData()
func configureTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(ArtiklerCell.self, forCellReuseIdentifier: "ArtiklerCell")
// remove separators for empty cells
tableView.tableFooterView = UIView()
// remove separators from cells
tableView.separatorStyle = .none
}
func loadData() {
db.collection("articles").getDocuments() { (QuerySnapshot, err) in
if let err = err {
print("Error getting documents : \(err)")
}
else {
for document in QuerySnapshot!.documents {
let documentID = document.documentID
let artiklerImageView = document.get("imageURL") as! URL
let artiklerTitleLabel = document.get("title") as! String
print(artiklerImageView, artiklerTitleLabel, documentID)
}
self.tableView.reloadData()
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("Tableview setup \(artiklerArray.count)")
return artiklerArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ArtiklerCell", for: indexPath) as! ArtiklerCell
let artikler = artiklerArray[indexPath.row]
print("Array is populated \(artiklerArray)")
return cell
}
}
ArtiklerCell.swift
import UIKit
import Firebase
class ArtiklerCell: UITableViewCell {
#IBOutlet weak var artiklerImageView: UIImageView!
#IBOutlet weak var artiklerTitleLabel: UILabel!
var db: Firestore!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
db = Firestore.firestore()
addSubview(artiklerImageView)
addSubview(artiklerTitleLabel)
configureImageView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureImageView() {
artiklerImageView.layer.cornerRadius = 20
artiklerImageView.clipsToBounds = true
}
}
When I try to run the app, I get an error message from the ArtiklerTableViewController.swift regarding the line let artikler = artiklerArray[indexPath.row] in the cellForRowAt function, saying 'Initialization of immutable value 'artikler' was never used; consider replacing with assignment to '_' or removing it'.
I see that this error message makes sense, but I have absolutely no idea what I should do instead.
Pardon my extreme lack of knowledge! I have spent many days now trying to look for the answers I need online without finding a solution. I think I am too inexperienced to correctly search for and absorb the necessary knowledge for this problem.
Any answer will be immensely appreciated!
Thanks in advance from a desperate girl who doesn't want to give up on learning iOS dev as I go through building an app.

You already have the strings in an array and got the artikler corresponding to the row of the cell, now you just need to set the title and the image. Also, you need to append each element to the array before reloading.
func loadData() {
db.collection("articles").getDocuments() { (QuerySnapshot, err) in
if let err = err {
print("Error getting documents : \(err)")
}
else {
for document in QuerySnapshot!.documents {
let documentID = document.documentID
let artiklerImageView = document.get("imageURL") as! URL
let artiklerTitleLabel = document.get("title") as! String
self.artiklerArray.append(artiklerTitleLabel)
}
self.tableView.reloadData()
}
}
}
...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ArtiklerCell", for: indexPath) as! ArtiklerCell
let artikler = artiklerArray[indexPath.row]
cell.artiklerTitleLabel.text = artikler
return cell
}

Related

How to disable Tableview DequeueReusableCell?

I am trying to load my tableview without using dequeueReusableCell, but it just crashes my app, cant figure out what i am doing wrong?
let cell = Tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SökrutaCell // THIS CODE WORKS FINE
let cell = SökrutaCell() // THIS CODE CRASHES - Unexpectedly found nil while unwrapping an optional
Would love if anyone could point me in the right direction so i can understand what is failing.
import UIKit
import Alamofire
class Sökruta: UIViewController {
var sökresultat = [Object2]()
#IBOutlet weak var Tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
GetRequest(Url: "https://randomurl.se")
Tableview.delegate = self
Tableview.dataSource = self
Tableview.backgroundColor = UIColor.white
// Do any additional setup after loading the view.
}
}
// MARK: - Delegate extension 1
extension Sökruta: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("you tapped me!")
}
}
// MARK: - Delegate extension 2
extension Sökruta: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sökresultat.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = Tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SökrutaCell // THIS CODE WORKS FINE
let cell = SökrutaCell() // THIS CODE CRASHES - Unexpectedly found nil while unwrapping an optional
cell.Söknamn.text = sökresultat[indexPath.row].displayname
if let url = URL(string: dontmindthiscode) {
DispatchQueue.global().async {
do {
let data = try Data(contentsOf: url)
DispatchQueue.main.async {
cell.Sökbild.image = UIImage(data: data)
}
} catch let err {
print("error: \(err.localizedDescription)")
}
}
}
else
{
DispatchQueue.main.async {
cell.Sökbild.image = UIImage(systemName: "eye.slash")
}
}
return cell
}
}
// MARK: - Extension functions
extension Sökruta{
// MARK: - GET REQUEST
func GetRequest(Url: String) {
// MARK: - Login details
let headers: HTTPHeaders = [
.authorization(username: "username", password: "password"),
.accept("application/json")]
// MARK: - Api request
AF.request(result, headers: headers).validate().responseJSON { response in
// MARK: - Check for errors
if let error = response.error
{
print (error)
return}
// MARK: - Print response
if response.response != nil
{ }
// MARK: - Print data
if response.data != nil
{
let decoder = JSONDecoder()
do
{
let api = try decoder.decode(Main2.self, from: response.data!)
self.sökresultat = api.objects
self.Tableview.reloadData()
}
catch {
print(error.localizedDescription)
print("Error in JSON parsing")
}
}
}
}// MARK: - END
}
This is my cell.swift code:
import UIKit
class SökrutaCell: UITableViewCell {
#IBOutlet weak var Sökbild: UIImageView!
#IBOutlet weak var Söknamn: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
You have a class with #IBOutlet references to a prototype cell in your storyboard. You can't use that cell prototype (with its custom layout) and have the outlets hooked up for you unless you use the dequeueReusableCell(withIdentifier:for:).
If your goal was to compare this against a non-reused cell, you could instantiate a UITableViewCell programmatically and use the built in textLabel and imageView properties. For example, you could:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "...")
cell.textLabel?.text = ...
cell.imageView?.image = ... // use a placeholder image here or else it won't show the image view at all!
someMethodToFetchImageAsynchronously { image in
// make sure this cell hasn't scrolled out of view!!!
guard let cell = tableView.cellForRow(at: indexPath) else { return }
// if still visible, update its image
cell.imageView?.image = image
}
return cell
}
Or you could consider more complicated programmatic patterns (where you add controls and configure them manually, which probably would be a more fair comparison), too. But the above is a fairly minimal implementation.
Needless to say, this pattern is not recommended, as you lose the storyboard cell prototype benefits and the performance/memory benefits of cell reuse. But if your goal was just to compare and contrast the memory, performance, and software design considerations, perhaps this helps you get your arms around it.
While I've attempted to answer your question, before I worried about the inherent performance of dequeued cells, your image retrieval mechanism is a far greater performance concern. You are fetching images using Data(contentsOf:), a non-cancelable network request. So, if you have hundred rows, and you quickly scroll down to rows 90..<100, the image retrieval for those 10 rows will be backlogged being the network requests for the first 90 rows! Also, are your images appropriately sized for the small image view in the cell? That can also observably impact performance and the smoothness of the scrolling.
There are a number of decent asynchronous image retrieval libraries out there. E.g. since you are already using Alamofire, I would suggest you consider AlamofireImage. This offers nice asynchronous image retrieval mechanisms, nice UIImageView extensions, the ability to cancel requests that are no longer needed, image caching, etc.
But proper asynchronous image retrieval for a table view is a non-trivial problem. An image processing library like AlamofireImage, KingFisher, SDWebImage, etc., can simplify this process for you.

sort tableViewCells by numbers inside a label

I try to sort the tableViewCells by numbers inside a label, so the cell which includes the highest number in a label should be last, and vice versa.
I tried it with different solutions like following, but it's simply not working, it also doesn't show any error code
I don't know if there is just a small mistake or if it is all completely wrong, but if so, I hope that you know a completely different way to solve it.
TableView:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// download jobs
jobsRef.observe(.value, with: { (snapshot) in
self.jobs.removeAll()
for child in snapshot.children {
let childSnapshot = child as! DataSnapshot
let job = Job(snapshot: childSnapshot)
print(job)
self.jobs.insert(job, at: 0)
}
filterLocation()
self.tableView.reloadData()
})
}
var jobArr = JobTableViewCell.jobDistance!.jobArr
func filterLocation() {
jobArr.sort() { $0.distance.text > $1.distance.text}
}
TableViewCell:
#IBOutlet weak var distance: UILabel!
static var jobDistance: JobTableViewCell?
var jobArr = [JobTableViewCell.jobDistance!.distance.text]
override func layoutSubviews() {
super.layoutSubviews()
JobTableViewCell.jobDistance = self
}
lets check out apple doc for the table view https://developer.apple.com/documentation/uikit/uitableviewdatasource
as it says there is method:
func tableView(UITableView, cellForRowAt: IndexPath) -> UITableViewCell
we can read it like "give me[UITableView] cell[-> UITableViewCell] for this index[cellForRowAt]"
so all we need is just map our data source to tableview indexes:
e.g.
we have datasource array of strings
var dataSource = ["String", "Very long string", "Str"]
sort...
> ["Str", "String", "Very long string"]
and then just provide our data to cell (your tableview must conform UITableViewDataSource protocol)
// Provide a cell object for each row.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Fetch a cell of the appropriate type.
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTypeIdentifier", for: indexPath)
// Configure the cell’s contents.
cell.textLabel!.text = dataSource[indexPath]
return cell
}
The problem is you sort another array jobArr
jobArr.sort() { $0.distance.text > $1.distance.text}
and append values to another one jobs

Swift retain UISegmentedControl values in UITableViewCells

I'm creating a quiz app with custom cells that include a label of questions and then an answer coming from a UISegmentedControl.
The values of the segmentedcontrols get changed when scrolling and this leads to an inaccurate score. I understand that this is due to UITableView reusing cells.
My tableview's datasource in my main vc is simply the labels for all my questions coming from a plist file.
The code for my custom tableviewcell class is
class QuestionsTableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var selection: UISegmentedControl!
var question: String = "" {
didSet {
if (question != oldValue) {
questionLabel.text = question
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//Just for testing
#IBAction func segmentChanged(_ sender: UISegmentedControl) {
print("value is ", sender.selectedSegmentIndex);
}
}
where the View is stored in an .XIB file.
And the code for my main vc is
class ViewController: UIViewController, UITableViewDataSource {
let questionsTableIdentifier = "QuestionsTableIdentifier"
#IBOutlet var tableView:UITableView!
var questionsArray = [String]();
var questionsCellArray = [QuestionsTableViewCell]();
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let path = Bundle.main.path(forResource:
"Questions", ofType: "plist")
questionsArray = NSArray(contentsOfFile: path!) as! [String]
tableView.register(QuestionsTableViewCell.self,
forCellReuseIdentifier: questionsTableIdentifier)
let xib = UINib(nibName: "QuestionsTableViewCell", bundle: nil)
tableView.register(xib,
forCellReuseIdentifier: questionsTableIdentifier)
tableView.rowHeight = 108;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questionsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: questionsTableIdentifier, for: indexPath)
as! QuestionsTableViewCell
let rowData = questionsArray[indexPath.row]
cell.question = rowData
return cell
}
#IBAction func calculate(_ sender: UIButton) {
var score = 0
for cell in tableView.visibleCells as! [QuestionsTableViewCell] {
score += cell.selection.selectedSegmentIndex
}
let msg = "Score is, \(score)"
print(msg)
}
#IBAction func reset(_ sender: UIButton) {
for cell in tableView.visibleCells as! [QuestionsTableViewCell] {
cell.selection.selectedSegmentIndex = 0;
}
}
}
What I'd like to do is just keep track of all 'selection' changes of the Questions cells in an array, and then use that array in cellForRowAt. I'm just confused as to how i can dynamically keep track of changes from a view in another class. I'm new to Swift and would like to solve this is a proper MVC fashion. Thanks
Instead of a simple string array as data source create a class holding the text and the selected index
class Question {
let text : String
var answerIndex : Int
init(text : String, answerIndex : Int = 0) {
self.text = text
self.answerIndex = answerIndex
}
}
Declare questionArray as
var questions = [Question]()
Populate the array in viewDidLoad with
let url = Bundle.main.url(forResource: "Questions", withExtension: "plist")!
let data = try! Data(contentsOf: url)
let questionsArray = try! PropertyListSerialization.propertyList(from: data, format: nil) as! [String]
questions = questionsArray.map {Question(text: $0)}
In the custom cell add a callback and call it in the segmentChanged method passing the selected index, the property question is not needed, the label is updated in cellForRow of the controller
class QuestionsTableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var selection: UISegmentedControl!
var callback : ((Int) -> ())?
#IBAction func segmentChanged(_ sender: UISegmentedControl) {
print("value is ", sender.selectedSegmentIndex)
callback?(sender.selectedSegmentIndex)
}
}
In cellForRow add the callback and update the model in the closure
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: questionsTableIdentifier, for: indexPath) as! QuestionsTableViewCell
let question = questions[indexPath.row]
cell.questionLabel.text = question.text
cell.selection.selectedSegmentIndex = question.answerIndex
cell.callback = { index in
question.answerIndex = index
}
return cell
}
To reset the segmented controls in the cells set the property in the model to 0 and reload the table view
#IBAction func reset(_ sender: UIButton) {
questions.forEach { $0.answerIndex = 0 }
self.tableView.reloadData()
}
Now you could calculate the score directly from the model instead of the view.
Don't try to use cells to hold information. As the user scrolls through your table view, cells that scroll out of view will get recycled and their field settings will be lost. Also, newly dequeued cells will have the settings from the last time they were used.
You need to refactor your code to read/write information into a data model. Using an array of Structs as a data model is a reasonable way to go. (Or, as vadian suggests in his answer, and array of Class objects, so you get reference semantics.)
You have an IBAction segmentChanged() in your custom cell class. The next trick is to notify the view controller when the user changes the selection, and to update cells when you set them up in cellForRowAt.
I suggest defining a protocol QuestionsTableViewCellProtocol, and have the view controller conform to that protocol:
protocol QuestionsTableViewCellProtocol {
func userSelected(segmentIndex: Int, inCell cell: UITableViewCell)
}
}
Add a delegate property to your QuestionsTableViewCell class:
class QuestionsTableViewCell: UITableViewCell {
weak var delegate: QuestionsTableViewCellProtocol?
//The rest of your class goes here...
}
Update your cell's segmentChanged() method to invoke the delegate's userSelected(segmentIndex:inCell:) method.
In your view controller's cellForRowAt, set the cell's delegate to self.
func userSelected(segmentIndex: Int, inCellCell cell: UITableViewCell) {
let indexPath = tableView.indexPath(for: cell)
let row = indexPath.row
//The code below assumes that you have an array of structs, `dataModel`, that
//has a property selectedIndex that remembers which cell is selected.
//Adjust the code below to match your actual array that keeps track of your data.
dataModel[row].selectedIndex = segmentIndex
}
Then update cellforRowAt() to use the data model to set the segment index on the newly dequeued cell to the correct index.
Also update your calculate() function to look at the values in your dataModel to calculate the score, NOT the tableView.
That's a rough idea. I left some details out as "an exercise for the reader." See if you can figure out how to make that work.

Append result arrays in Realm

Good morning everybody,
I'm having a table view which display objects saved from 2 different classes. Im going to combine these result into one array to display in tableView. Here is my code:
import UIKit
import RealmSwift
class BookmarksVC: UIViewController,UITableViewDelegate,UITableViewDataSource {
var articleList: Results<DynamicObject>!
var documentList: Results<DynamicObject>!
var list = [Any]()
var article: Any!
var searchBar:UISearchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 280, height: 20))
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "BookmarkCell", bundle: nil), forCellReuseIdentifier: "bookmarkCell")
tableView.delegate = self
tableView.dataSource = self
drawNavBarUI(navigationItem: self.navigationItem, searchBar: searchBar)
loadDataAndUpdateUI()
}
func loadDataAndUpdateUI() {
articleList = realm.dynamicObjects(NewsArticle.className())
documentList = realm.dynamicObjects(Documents.className())
list.append(articleList)
list.append(documentList)
tableView.setEditing(false, animated: true)
tableView.reloadData()
}
But the result was:
it lead to the tableview just displayed only 2 cell. I tried to use append(ContentsOf:) but Xcode forced it back to append(). This is my first time using Realm, so i might not have deep understanding about it. So anyone can help me to solve this problem?. Thank you guys for reading and sorry for my bad English.
Katsumi from Realm here. We don't recommend to copy Results objects to Array. It loses the useful ability of Results such like auto-updating, lazy loading etc. Also, using DynamicObject loses type safety.
You can use Results as data source directly even if you have multiple Results objects. Like the following:
class BookmarksVC: UIViewController,UITableViewDelegate,UITableViewDataSource {
var articleList: Results<NewsArticle>!
var documentList: Results<Documents>!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
...
loadDataAndUpdateUI()
}
func loadDataAndUpdateUI() {
articleList = realm.objects(NewsArticle.self)
documentList = realm.objects(Documents.self)
...
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return articleList.count + documentList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
if indexPath.row < articleList.count {
let article = articleList[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "bookmarkCell", for: indexPath) as! BookmarkCell
cell.configureCell(article: article)
return cell
} else {
let document = documentList[indexPath.row - articleList.count]
...
}
}
...
}
First of all, you shouldn't use an Array of Any. The problem is caused, because Swift converts the Results collection to a single Any object.
You should use append(contentsOf: ), since this is the function that accepts a sequence as an input and not just a single element.
Since you only want to store Realm objects in list, change it to a Realm List of DynamicObjects and call append after converting the Results collection to a List.
var list = List<DynamicObjects>()
list.append(contentsOf: List(articleList))
list.append(contentsOf: List(documentList))

SWIFT: Data model for "Like" button functionality in iOS app

I'm creating a playlist app (Mock-Up Below) using Swift and Parse. Each user has the ability add a song (or multiple songs) to the TableView and "Like" or "Dislike" (toggle style) as many songs as they like, including their own. This functionality is very similar to the Instagram "Like" button behaviour.
I'm having a bit of trouble conceptualizing the data model. As shown below, I have a User table and a Playlist table (with all of the added songs):
User Table:
Playlist Table:
I'm having trouble with the next step, which is storing the "Like" data for each user and each song.
UPDATED: I've added a column in the 'PlaylistData' table in Parse called "userVotes". As you can see, I'm appending all of the data into an array called 'voters'. For some reason, I'm getting a fatal run time error - 'fatal error: unexpectedly found nil while unwrapping an Optional value'.
import UIKit
import Parse
class MusicPlaylistTableViewController: UITableViewController {
var usernames = [String]()
var songs = [String]()
var voters = [String]()
var numVotes = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorColor = UIColor.grayColor()
let query = PFQuery(className:"PlaylistData")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects! as? [PFObject] {
self.usernames.removeAll()
self.songs.removeAll()
self.voters.removeAll()
for object in objects {
let username = object["username"] as? String
self.usernames.append(username!)
let track = object["song"] as? String
self.songs.append(track!)
self.voters = object["userVotes"] as! [String]
print(self.voters)
}
self.tableView.reloadData()
}
} else {
print(error)
}
}
}
override func viewWillAppear(animated: Bool) {
}
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 cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.votes.text = "\(numVotes)"
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
}
}
I've also created a TableViewCell swift file for the prototype cell:
import UIKit
import Parse
class TrackTableViewCell: UITableViewCell {
var numVotes = 0
#IBOutlet weak var songTitle: UILabel!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var votes: UILabel!
#IBAction func voteButton(sender: UIButton) {
self.numVotes = self.numVotes + 1
self.votes.text = "\(self.numVotes)"
}
}
At this point, all it does is when the heart is clicked, it increases the vote count by 1 on screen (the user can do this as many times as possible, no data is stored in the database). What I need help with is the best way to implement table(s) which allow me to keep track of which users have voted for each song (or not). I know I need a TRUE / FALSE column somewhere, but I can't seem to figure out how to model it. Any suggestions or links to SWIFT tutorials would be greatly appreciated. A simple explanation on what tables to create (or what columns to add to existing tables) would help the best. Thanks!

Resources