I am trying to make a comment section for my open source social media app. I have a table of posts. When you click a post in this table, it takes you to the MainViewController, where you can read the comments on those posts and post your own comment. The Post class is as follows:
import Foundation
class Post {
var id:String
var title: String
var text:String
var createdAt:Date
var comment: [String] = []
init(id: String, title: String,text:String, timestamp:Double, comment: [String] = []) {
self.id = id
self.title = title
self.text = text
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, data:[String:Any]) -> Post? {
if let title = data["text"] as? String,
let text = data["title"] as? String,
let timestamp = data["timestamp"] as? Double {
return Post(id: key, title: title, text: text, timestamp:timestamp, comment: [])
}
return nil
}
}
And the MainTextViewController has the following code:
import Foundation
import UIKit
import Firebase
class MainTextView: UIViewController, UITextViewDelegate{
#IBOutlet weak var titleText: UILabel!
#IBOutlet weak var mainText: UILabel!
#IBOutlet weak var commentsTable: UITableView!
#IBOutlet weak var commentPlaceHolder: UILabel!
#IBOutlet weak var newCommentLabel: UITextView!
weak var delegate:NewPostVCDelegate?
#IBAction func reply(_ sender: UIButton) {
// Firebase code here
let postRef = Database.database().reference().child("posts").childByAutoId()
let postObject = [
"comment": newCommentLabel.text,
"timestamp": [".sv": "timestamp"]
] as [String : Any]
postRef.setValue(postObject, withCompletionBlock: { error, ref in
if error == nil {
self.delegate!.didUploadPost(withID: ref.key!)
self.dismiss(animated: true, completion: nil)
} else {
// Handle error
}
})
newCommentLabel.text = String()
commentPlaceHolder.isHidden = false
}
var post: Post?
// MARK: - View Controller LifeCycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setMain()
}
override func viewDidLoad() {
super.viewDidLoad()
print(delegate!)
commentsTable.dataSource = post?.comment as? UITableViewDataSource
newCommentLabel.delegate = self
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return post!.comment.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let label = UILabel(frame: CGRect(x:0, y:0, width:200, height:50))
cell.addSubview(label)
return cell
}
// UITableViewDelegate Functions
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50
}
private func setMain() {
guard let post = self.post else {
return
}
titleText.text = post.text
mainText.text = post.title
}
func textViewDidChange(_ commentView: UITextView) {
commentPlaceHolder.isHidden = !newCommentLabel.text.isEmpty
}
}
Here is my database structure:
{
"posts" : {
"-LhaxLOSY3UI7tDUrCA_" : {
"text" : "Nelson",
"timestamp" : 1560800488059,
"title" : "Hey\t"
},
"-LhaxbnjgDP7tdb7Eq_4" : {
"text" : "Lol",
"timestamp" : 1560800558514,
"title" : "How’s it going"
},
"comment" : {
"comment" : "Howdy"
}
}
}
I want that when I make a comment, it appends the comments array for the post with a new comment. Then everyone can see the comments in the commentsTable as a collection of strings from the array with the oldest one on top.
At the moment, creating a new comment makes a new post in Firebase with just a comment as a single string and a timestamp. How would you fix this issue so that the post button appends the table and the commentsTable shows the strings from the array? Let me know if you need me to post more details. Thank you for the help.
Without going overboard with a bunch of code, conceptually, if you want to have a series of posts, and then each post can additionally have comments, here's one option for a structure.
posts
post_id_0
text: "some text"
timestamp: "20190601"
title: "post title"
post_uid: "uid_0"
comments
comment_id_0
belongs_to_post: "post_id_0"
comment: "a comment about the post"
timestamp: "20190601"
comment_uid: "uid_49"
comment_id_1
belongs_to_post: "post_id_0"
comment: "check out that first post!"
timestamp: "20190602"
comment_uid: "uid_102"
users
uid_0
name: "Leroy"
then attach observers to posts and comments. When a new post is posted, you'll be notified of that post and can add it to your tableView datasource and refresh the tableView.
When a new comment is added, you'll be notified of that comment and add it to the comments dataSource and reload the comments tableView. To add a new post:
let thisPostRef = your_firebase.posts.childByAutoId()
thisPostRef.setValue(your_post_data)
and to add a comment
let postKey = the_post.key
let commentRef = your_firebase.comments.childByAutoId()
commentRef.setValue(your_comment_data)
and your_comment_data would include a child node 'belongs_to_post: postKey'
You can also watch for comments on certain posts, made by certain users or even query for comments by date or in a date range.
Code wise, both posts and comments nodes are created with .childByAutoId - it's best practice to disassociate node keys from the data they contain, unless it going to be static data, like a uid.
If you want to add a bit more flexibility, you could keep a child node within each posts of it's related comments as well.
posts
post_id_0
text: "some text"
timestamp: "20190601"
title: "post title"
post_uid: "uid_0"
comments:
comment_id_0: true
comment_id_1: true
but that depends on what kinds of queries you want to run.
Note: I separate the comments structure from the posts the posts node as denormalizing your data is very beneficial when running queries.
Related
My app crashes when I click a cell in my tableView of recent posts. The click is supposed to segue me to the MainTextView which has the postReplyButton. The segue worked until I started experimenting with creating comments for the posts.
Here is the MainTextView code:
import Foundation
import UIKit
import Firebase
class MainTextView: UIViewController {
#IBOutlet weak var titleText: UILabel!
#IBOutlet weak var mainText: UILabel!
#IBOutlet weak var commentPlaceHolder: UILabel!
#IBOutlet weak var newCommentLabel: UITextView!
var delegate:NewPostVCDelegate?
#IBAction func postReplyButton() {
// Firebase code here
let postRef = Database.database().reference().child("posts").childByAutoId()
let postObject = [
"comment": newCommentLabel.text,
"timestamp": [".sv": "timestamp"]
] as [String : Any]
postRef.setValue(postObject, withCompletionBlock: { error, ref in
if error == nil {
self.delegate!.didUploadPost(withID: ref.key!)
self.dismiss(animated: true, completion: nil)
} else {
// Handle error
}
})
newCommentLabel.text = String()
commentPlaceHolder.isHidden = false
}
var post: Post?
// MARK: - View Controller LifeCycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setMain()
}
override func viewDidLoad() {
super.viewDidLoad()
newCommentLabel.delegate = self as! UITextViewDelegate
}
private func setMain() {
guard let post = self.post else {
return
}
titleText.text = post.text
mainText.text = post.title
}
func textViewDidChange(_commentView: UITextView) {
commentPlaceHolder.isHidden = !newCommentLabel.text.isEmpty
}
}
For reference, here is my Post class code:
import Foundation
class Post {
var id:String
var title: String
var text:String
var createdAt:Date
var comment: [String] = []
init(id: String, title: String,text:String, timestamp:Double, comment: [String] = []) {
self.id = id
self.title = title
self.text = text
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, data:[String:Any]) -> Post? {
if let title = data["text"] as? String,
let text = data["title"] as? String,
let timestamp = data["timestamp"] as? Double {
return Post(id: key, title: title, text: text, timestamp:timestamp, comment: [])
}
return nil
}
}
I suspect the issue may be with the delegate, which was declared as such in my NewPostViewController:
protocol NewPostVCDelegate {
func didUploadPost(withID id:String)
}
I have tried troubleshooting the storyboard, but everything seems to be in place. Is there an issue of the reuse of the protocol or perhaps the change of adding comments to the Post class itself? Maybe the issue is that I do not in fact want to upload a new post, but really I just want to add a comment to an existing post. If this is the case, how would I change the delegate or create a new one? I can provide more detail if needed. Thank you for your help.
This usually happens if you have an IBOutlet that was created previously with the same postReplyButton name. To check if your app has any other Outlet with the same name go to the Search section in your project and search for postReplyButton and see if you get multiple results for that name. If you do then click on the one which you don't need and delete it from the properties section.
If you have any Outlet which has a bad connection you will see something like this in the properties sections when you click on any one of the search result for postReplyButton
If that does not work then try renaming the Outlet entirely and see if that fixes the problem.
EDITED:
For your issue that you mentioned in the comments try this.
Instead of casting your newCommentLabel as an optional type of UITextViewDelegate just extend your viewController to conform to UITextViewDelegate. This should solve the issue.
class MainTextView: UIViewController, UITextViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
newCommentLabel.delegate = self
}
}
Once you add UITextViewDelegate to your viewController you will no longer get the warning in viewDidLoad to cast newCommentLabel as an optional of type UITextViewDelegate.
I have created an app where users can generate posts that are added to a postTableView. Users can then click on any of the cells of postTableView to go to a unique view with the title and text of the post along with a commentTableView filled with user generated comments. Below the commentTableView is a textView that you can write your comment in and a button allowing you to submit your comment. I am trying to code my app so that when you press the button, the text that you wrote in the textView is appended to an array of unique comments for that post. Those comments populate the commentTableView. The following is my current flawed attempt:
Here is the Post Class:
import Foundation
class Post {
var id:String
var title: String
var text:String
var createdAt:Date
var comment: [String] = []
init(id: String, title: String,text:String, timestamp:Double, comment: [String] = []) {
self.id = id
self.title = title
self.text = text
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, data:[String:Any]) -> Post? {
if let title = data["text"] as? String,
let text = data["title"] as? String,
let timestamp = data["timestamp"] as? Double {
return Post(id: key, title: title, text: text, timestamp:timestamp, comment: [])
}
return nil
}
}
Here is my current view controller that you get when you click on any of the cells from the postTableView:
import Foundation
import UIKit
import Firebase
class MainTextView: UIViewController {
#IBOutlet weak var titleText: UILabel!
#IBOutlet weak var mainText: UILabel!
#IBOutlet weak var commentPlaceHolder: UILabel!
#IBOutlet weak var newCommentLabel: UITextView!
var delegate:NewPostVCDelegate?
#IBAction func postReplyButton() {
// Firebase code here
let postRef = Database.database().reference().child("posts").childByAutoId()
let postObject = [
"comment": newCommentLabel.text,
"timestamp": [".sv": "timestamp"]
] as [String : Any]
postRef.setValue(postObject, withCompletionBlock: { error, ref in
if error == nil {
self.delegate!.didUploadPost(withID: ref.key!)
self.dismiss(animated: true, completion: nil)
} else {
// Handle error
}
})
newCommentLabel.text = String()
commentPlaceHolder.isHidden = false
}
var post: Post?
// MARK: - View Controller LifeCycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setMain()
}
override func viewDidLoad() {
super.viewDidLoad()
newCommentLabel.delegate = self as! UITextViewDelegate
}
private func setMain() {
guard let post = self.post else {
return
}
titleText.text = post.text
mainText.text = post.title
}
func textViewDidChange(_commentView: UITextView) {
commentPlaceHolder.isHidden = !newCommentLabel.text.isEmpty
}
}
How can I fix my errors and programmatically execute my vision of populating my comment section with user for each post?
For
Class 'MainTextView' has no initializers
Replace
var delegate:NewPostVCDelegate
with
var delegate:NewPostVCDelegate?
I am new to Swift. I know how to get a single piece of data from Firebase, but when I try to get a list of data into an array, I get no error or no data. Please help me. I have been struggled with this for days now.
I want to add data from Firebase into array,
I have created json file with list of categories and imported in firebase.
My JSON file look like this:
{
"Category" : [ {
"categoryId" : "1",
"imageName" : "cat_001.png",
"title" : "CAT"
}, {
"categoryId" : "2",
"imageName" : "dog_001.png",
"title" : "DOG"
}, {
"categoryId" : "3",
"imageName" : "fish_001.png",
"title" : "FISH"
}, {
"categoryId" : "4",
"imageName" : "bird_001.png",
"title" : "BRID"
}]
}
Firebase database looks like
this
Category class looks like this
struct Category {
private(set) public var title: String
private(set) public var imageName: String
init(title: String, imageName: String) {
self.title = title
self.imageName = imageName
}
}
I use custom cell to show my data and here is my custom cell class
class CategoryCell: UITableViewCell {
#IBOutlet weak var categoryImage: UIImageView!
#IBOutlet weak var categoryTitle: UILabel!
func updateViews(category: Category){
categoryImage.image = UIImage(named: category.imageName)
categoryTitle.text = category.title
}
}
And I use DataService class to get data, right now data is hard coded and its working fine.
class DataService{
static let instance = DataService()
// How to add data from firebase in here`?
private let categories = [Category(title: "CAT", imageName: "cat_001"),
Category(title: "DOG", imageName: "dog_001"),
Category(title: "FISH", imageName: "fish_001")]
func getCategories() -> [Category]{
return categories
}
}
and finally here is my ViewController
class CategoriesVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var categoryTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
categoryTable.dataSource = self
categoryTable.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return DataService.instance.getCategories().count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryCell") as? CategoryCell {
let category = DataService.instance.getCategories()[indexPath.row]
cell.updateViews(category: category)
return cell
}else{
return CategoryCell()
}
}
}
I am going to add more categories in the future.
With hard coded data my app looks like this and i want to achieve same result with data from firebase.
Try it like this, just use an array of Category's for the tableview datasource:
var tableData = [Category]()
then in viewDidLoad, set up a firebase observer to update that array any time there are changes to the Category node in firebase:
ref.child("Category").observe(.value, with: { snapshot in
var newTableData: [Category] = []
for category in snapshot.children {
let dict = category.value as! [String: AnyObject]
let title = dict["title"] as! String
let imageName = dict["imageName"] as! String
let newCategory = Category(title: title,
imageName: imageName)
newTableData.append(newCategory)
}
self.tableData = newTableData
self.tableview.reloadData()
})
I'm working on a car rental app, which accepts user's input and putting it in my SQLite Database.
Inside my tableview viewcontroller, it is displaying the informations fine.
Example:
Cell 1: Toyota, Philippines, 5000
Cell 2: Nissan, America, 1000
Cell 3: Mitsubishi, England, 2000
The problem is, whenever I search, for example I searched the "england", the only right data it is displaying is only the location. So it will display like this:
Cell 1: Toyota, England, 5000
which is Toyota and 5000 is coming from the index 0. and the only right data is England.
My desired result whenever I search "england":
Cell 1: Mitsubishi, England, 2000
Please help me fixing the car type and rate to display it also.
This is my code inside my table view controller:
import UIKit
import SQLite
class CarList: UIViewController, UITableViewDataSource, UITableViewDelegate,
UISearchBarDelegate {
#IBOutlet var tableView: UITableView!
#IBOutlet var searchBar: UISearchBar!
//variables I used to append my database
var carType = [String]()
var rate = [String]()
var location = [String]()
//variables I used to append my filtered data for searchbar
var filteredLocation: [String]!
var filteredCar: [String]!
var filteredRate: [String]!
var img = [UIImage(named: "Toyota"), UIImage(named: "Nissan")]
override func viewDidLoad() {
super.viewDidLoad()
searchBar.placeholder = "Search Location"
do{
let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileUrl = documentDirectory.appendingPathComponent("users").appendingPathExtension("sqlite3")
let database = try Connection(fileUrl.path)
Variables.database = database
}catch {
print(error)
}
//appending my database to my array
do{
let users = try Variables.database.prepare(Variables.rTable)
for user in users {
carType.append(user[Variables.rCar])
rate.append(user[Variables.rRate])
location.append(user[Variables.rLocation])
}
}catch{
print(error)
}
searchBar.delegate = self
//assigning the array to filtered data
filteredLocation = location
filteredCar = carType
filteredRate = rate
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredLocation.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CarListCell
cell.carType.text = "Car Type: " + filteredCar[indexPath.row]
cell.rate.text = "Location: " + filteredLocation[indexPath.row]
cell.carImage.image = UIImage(named: filteredCar[indexPath.row]+".jpg")
return (cell)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredLocation = searchText.isEmpty ? location : location.filter({(dataString: String) -> Bool in
return dataString.range(of: searchText, options: .caseInsensitive) != nil
})
tableView.reloadData()
}
//below is the code when I clicked on the table view cell, it will pass the data.
//but the filtered location is the only one working.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "info" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destination as! CarInfo
controller.getCar = filteredCar[indexPath.row]
controller.getRate = filteredRate[indexPath.row]
controller.getLocation = filteredLocation[indexPath.row]
}
}
}
} // End Class
And this is my database table in case you need it, I separated it using Variables.swift.
import Foundation
import UIKit
import SQLite
class Variables: UIViewController{
var database: Connection!
let rTable = Table("rTable")
let rId = Expression<Int>("rId")
let rCar= Expression<String>("rCar")
let rLocation = Expression<String>("rLocation")
let rRate = Expression<String>("rRate")
}
Rather than make 3 arrays for your data, you can make object for them
class Car{
var carType:String?
var location:String?
var rate:String?
}
Then rather
var filteredLocation: [String]!
var filteredCar: [String]!
var filteredRate: [String]!
make this
var cars = [Car]()
and rather than
for user in users {
carType.append(user[Variables.rCar])
rate.append(user[Variables.rRate])
location.append(user[Variables.rLocation])
}
make this
for user in users {
let car = Car()
car.carType = user[Variables.rCar]
car.location = user[Variables.rLocation]
car.rate = user[Variables.rRate]
cars.append(car)
}
and cellForRow change it to
cell.carType.text = "Car Type: " + cars[indexPath.row].carType
cell.rate.text = "Location: " + cars[indexPath.row].rate
cell.carImage.image = UIImage(named: cars[indexPath.row].carType+".jpg")
and the important thing is that
filteredCars = cars.filter{
$0.carType.lowercased == searchText.lowercased}
}
where filteredCars is array of car object . Hope this help you .
I am trying to build an app that is loading data from firebase-database.
Saving members to Firebase is working without any problems. Load members from Firebase to my UITableView is working then I am sorting the members and add respectively member under sections header according to first names first letter(A, B, C, etc as seen in iOS contact app) and this is working as well however my problem occur after I have loaded all my users and for example go to Tab 1 and then switch back to Members Tab all displayed members/cells are duplicated. If I repeat the same procedure switching tabs back and forth all cells triplicate and it goes on.
I have searched different sources for a solution but I can not find anything that is similar.
Does anyone know a solution or what I an doing wrong?
Thanks!
My Viewcontroller:
import Foundation
import UIKit
class MembersTableViewController: UITableViewController {
var FBref = FIRDatabaseReference()
var members: [Member] = []
var membersDict = [String: [String]]()
var memberSectionTitles = [String]()
// TODO: Implement user.
//var user: AdminUser!
let fakeuservariable = "fakeuser"
#IBOutlet var memberListTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
loadDataFromFirebase()
createFirstnameDict()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return memberSectionTitles.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let firstLetterKey = memberSectionTitles[section]
if let firstnameValues = membersDict[firstLetterKey] {
return firstnameValues.count
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return memberSectionTitles[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "membercell", for: indexPath)
let firstLetterKey = memberSectionTitles[indexPath.section]
if let firstnameValues = membersDict[firstLetterKey] {
cell.textLabel?.text = firstnameValues[indexPath.row]
// Not working
//let memberDetails = members[indexPath.row]
//cell.detailTextLabel!.text = "Amount left: \(memberDetails.memberamount)"
}
return cell
}
func createFirstnameDict() {
for firstname in members {
var firstLetter = firstname.firstname
let firstnameKey = firstLetter.substring(to: firstLetter.characters.index(firstLetter.startIndex, offsetBy: 1))
if var memberValues = membersDict[firstnameKey] {
memberValues.append(firstLetter)
membersDict[firstnameKey] = memberValues
} else {
membersDict[firstnameKey] = [firstLetter]
}
}
memberSectionTitles = [String](membersDict.keys)
memberSectionTitles = memberSectionTitles.sorted { $0 < $1 }
}
func loadDataFromFirebase() {
let FBref = FIRDatabase.database().reference()
FBref.child("member-list").observeSingleEvent(of: .value, with: { (snapshot) in
var resultItem: [Member] = []
for item in snapshot.children {
let memberItem = Member(snapshot: item as! FIRDataSnapshot)
resultItem.append(memberItem)
}
self.members = resultItem
self.createFirstnameDict()
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
}
My Member model:
import Foundation
struct Member {
let firstname: String
let lastname: String
let email: String
let phonenumber: String
let socialsecuritynr: String
let memberamount: String
let addedByUser: String
let key: String
let ref: FIRDatabaseReference?
init(firstname: String, lastname: String, email: String, phonenumber: String, socialsecuritynr: String, memberamount: String, addedByUser: String, key: String = "") {
self.key = key
self.firstname = firstname
self.lastname = lastname
self.email = email
self.phonenumber = phonenumber
self.socialsecuritynr = socialsecuritynr
self.memberamount = memberamount
self.addedByUser = addedByUser
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
firstname = snapshotValue["firstname"] as! String
lastname = snapshotValue["lastname"] as! String
email = snapshotValue["email"] as! String
phonenumber = snapshotValue["phonenumber"] as! String
socialsecuritynr = snapshotValue["socialsecuritynr"] as! String
memberamount = snapshotValue["memberamount"] as! String
addedByUser = snapshotValue["addedByUser"] as! String
ref = snapshot.ref
}
func toAnyObject() -> Any {
return ["firstname": firstname, "lastname": lastname, "email": email, "phonenumber": phonenumber, "socialsecuritynr": socialsecuritynr, "memberamount":memberamount, "addedByUser": addedByUser]
}
}
This is my TableView before and after:
The issue is arising from the placement of your methods that load the data which are wrongly in viewDidAppear:
loadDataFromFirebase()
createFirstnameDict()
This means that each time your view appears your data is loaded again and again. To fix the problem move these methods into viewDidLoad and you wont get the duplication issues. So you should now have:
override func viewDidLoad() {
super.viewDidLoad()
loadDataFromFirebase()
createFirstnameDict()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
What I recommend you, is that you clear all your arrays that you populate on your before event listener. This way you make sure that when it come back from another view it will not have old data. Something like this:
self.members.removeAll()
You are displaying the data from membersDict in your cell.textlabel .
Each time your view(when you switch tabs) loads, it calls loadDataFromFirebase() .
Here, all the values get loaded again and get appended to your membersValues which you then store in membersDict.
A new instance of membersDict will not get created since you are not declaring them inside of viewDidLoad(). You have declared them inside the class but outside any function.
What append does is add an element at the end of the array. It does not overwrite the element. So if you have an array with two names, appending a name will make that your third name and not overwrite any existing names.
Each time you load the view, you are appending the names to an array that already consists of the names. This is what is causing the duplication.
Try printing the value of your membersDict or membersValues, to check if you are duplicating.
You can solve this by declaring an instance of membersDict locally such that an empty variable is created each time and use that to display data.
Hope this helps.
From my understanding and experience, you load firebase data in
override func viewDidLoad() {
super.viewDidLoad()
loadFirebaseData()
}
Your newly created data from any other view controller will appear on your table when you return to it, because your observers are still listening unless you have told them to stop listening when moving to other views.
Therefore, anytime new data appears in Firebase, your table will automatically display it.