Populating tableView with firebase database - ios

i am trying to populate my tableView with firebase database.
Here is the code:-
import UIKit
import Firebase
class FriendsListViewController: UIViewController , UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var friendsListTableView: UITableView!
let ref = FIRDatabase.database().reference()
var FIRControllerClassHandle : FIRControllerClass = FIRControllerClass()
var imageCell = [UIImage]()
var username = [String]()
var userDesc = [String]()
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
friendsListTableView.alpha = 0
friendsListTableView.delegate = self
friendsListTableView.dataSource = self
populateTable({
self.friendsListTableView.reloadData()
})
}
func populateTable(completionBlock : (() -> Void)){
FIRControllerClassHandle.retrieveFriendListDatabase { (userIdA) in
for a in 1 ... userIdA.count-1 {
repeat {
self.FIRControllerClassHandle.retrieveStorageForFriendListCell(userIdA[a] as! String, completion: { (image) in
print("image transferred in the friendlist block : \(image)")
print("user id in friendList : \(userIdA[a])")
self.imageCell.append(image)
})
self.FIRControllerClassHandle.retrieveDatabaseForFriendListCell(userIdA[a] as! String, completion: { (profile) in
self.username.append((profile["username"] as? String)!)
self.userDesc.append((profile["briefDecription"] as? String)!)
completionBlock()
})
} while(a <= userIdA.count-1)
}
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("username count in the no of rows : \(username.count)")
return username.count ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("username in cellForIndexpath : \(self.username)")
let cell = friendsListTableView.dequeueReusableCellWithIdentifier("friendListCell") as! FriendsListTableViewCell
cell.friendListProfileName.text = username[indexPath.row]
cell.friendListProfileDescription.text = userDesc[indexPath.row]
cell.friendListProfilePicture.image = imageCell[indexPath.row]
return cell
}
#IBAction func backBtnAction(sender: UIButton) {
let homePageScene = self.navigationController?.storyboard?.instantiateViewControllerWithIdentifier("HomePageFeedViewControllerVC_ID") as! HomePageFeedViewController
self.navigationController?.pushViewController(homePageScene, animated: true)
}
}
This is running an infinite loop,
userIdA is the array in which i have stored all of my user.uid
self.FIRControllerClassHandle.retrieveStorageForFriendListCell is function in the separate FIRController class that is returning the profile picture of the user
similarly FIRControllerClassHandle.retrieveDatabaseForFriendListCell for retrieving database
How would i go around this?

You have two loops nested within in each other:
for a in 1 ... userIdA.count-1 {
repeat{
// ...
}while(a <= userIdA.count-1)
}
In the inner loop, a does not change, and therefore it will loop forever. I guess you just want the other loop.

Related

Trying to erase duplicated values in array retrieved from firebase in swift

I am trying to retrieve the value called memberJobfrom a firebase dict. After I retrieved it, the goal is to erase the duplicates, showing the unique values in a TableView.
The problem is that jobsis empty but memberJobactually has the values while looping over.
Maybe someone can help me! :)
import UIKit
import FirebaseDatabase
import Foundation
import FirebaseFirestoreSwift
import CodableFirebase
class ProjectCharacterViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var specTxt: UITextField!
#IBOutlet weak var difficultyTxt: UITextField!
#IBOutlet weak var budgetTxt: UITextField!
#IBOutlet weak var tableView: UITableView!
var member = [TeamMember]()
var jobs: [String] = []
var uniqueJobs = [MemberJobsStruct]()
var soloJobs: [String] = []
var singleJobs: [String] = []
var test = ["Hallo", "Birne", "Apfel"]
override func viewDidLoad() {
super.viewDidLoad()
getJobs(for: User.current) { (memberJob) in
self.uniqueJobs = memberJob
}
soloJobs = removeDuplicates(array: jobs)
print("SoloJobs :", soloJobs)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
// MARK: - Functions
func gettheJob() {
soloJobs = removeDuplicates(array: jobs)
print("These are the unique Jobs: ", soloJobs)
}
func getJobs(for user: User, completion: #escaping ([MemberJobsStruct]) -> Void) {
let ref = Database.database().reference().child("team").child(user.uid)
ref.observe(DataEventType.value, with: { snapshot in
for case let child as DataSnapshot in snapshot.children {
guard let value = child.value as? [String: Any] else {
return completion ([])
}
let memberJob = value["memberJob"] as! String
self.jobs.append(memberJob)
}
})
}
func removeDuplicates(array: [String]) -> [String] {
var encountered = Set<String>()
var result: [String] = []
for value in array {
if encountered.contains(value) {
// Do not add a duplicate element.
}
else {
// Add value to the set.
encountered.insert(value)
// ... Append the value.
result.append(value)
}
}
return result
}
}
// MARK: - UITableViewDataSource
extension ProjectCharacterViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return soloJobs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let job = jobs[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectCharacterTableViewCell") as! ProjectCharacterTableViewCell
cell.jobLabel.text = soloJobs[indexPath.row]
return cell
}
}
// MARK: - UITableViewDelegate
extension ProjectCharacterViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
Update: I tried to simply make a new array soloJobsout of jobsbut even this is not working. what is the right approach to do something like this? right now I tried it several ways including this one but nothings working...
func getJobs(for user: User, completion: #escaping ([MemberJobsStruct]) -> Void) {
var jobs: [String] = []
let ref = Database.database().reference().child("team").child(user.uid)
ref.observe(DataEventType.value, with: { snapshot in
for case let child as DataSnapshot in snapshot.children {
guard let value = child.value as? [String: Any] else {
return completion ([])
}
let memberJob = value["memberJob"] as! String
jobs.append(memberJob)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
soloJobs = jobs
}
You're probably just missing the part where you should reload the UITableView after the getJobs method has appended the jobs.
func getJobs(for user: User, completion: #escaping ([MemberJobsStruct]) -> Void) {
//...
ref.observe(DataEventType.value, with: { snapshot in
for case let child as DataSnapshot in snapshot.children {
//...
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
Update: For getting the Unique objects from an array using the extension method from here.

I tried to retrieving data from firebase database to tableview but I just got one element

I tried to retrieving data from Firebase database to tableview in Xcode
but I just got one element even if I have a lot of element in the database.
I followed a tutorial, I put return sonsList.count to numberOfRowsInSection as suppose but nothing happen.
Here is my code:
import UIKit
import Firebase
import FirebaseDatabase
class sons {
let name : String!
//let place : String!
init(title_String : String!){
self.name = title_String
// self.place = place_String
}
}
class sonsTableViewController: UITableViewController {
var ref:DatabaseReference!
//var sons = [String]()
var newSon: String = ""
let cellId = "cellId"
var refHandel : uint!
var sonsList = [sons]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
ref.child("name").queryOrderedByKey().observeSingleEvent(of: .childAdded, with: { snapshot in
let value = snapshot.value as? NSDictionary
let name = value!["name"] as! String
self.sonsList.append(sons(title_String : name))
self.tableView.reloadData()
})
//fetchName()
}
func fetchName() {
}
#IBAction func cancel(segue:UIStoryboardSegue) {
}
#IBAction func done(segue:UIStoryboardSegue) {
var sonDetailVC = segue.source as! addSonViewController
newSon = sonDetailVC.name
// sons.append(newSon)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sonsList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let label = cell?.viewWithTag(1) as! UILabel
label.text = sonsList[indexPath.row].name
return cell!
}
}
You have issues in your Database query.
You append only one value in sonsList.
ref = Database.database().reference()
ref.child("name").queryOrderedByKey().observeSingleEvent(of: .childAdded, with: { snapshot in
//Parse snapshot value correctly it is array or not.
if let dicValue = snapshot.value as? [String : Any] {
for (key,value) in dicValue {
let name = value["name"] as? String
self.sonsList.append(sons(title_String : name))
}
self.tableView.reloadData()
}
})
Please refer this link for Get data in firebase Database.
https://firebase.google.com/docs/database/ios/read-and-write

How to Filter a search with an objects properties efficiently in swift?

Hey guys i've searched for hours and still cant find a proper way to search though my data base. I have an array of contact objects that have a username and name property and I have a "add user" view controller where the GOAL is to loop through all the users in my data base , and when searching , it widdles down the users in a UITABLEVIEW this is what I have so far.
Cliff notes of code below:
I get all my user objects from my database and store them in an array of type [contact] called "results" (custom object) then i attempt to filter the results and store those into a new array called "filteredData" Contact has type "userName" (String) which I would like to filter results by
import UIKit
import Firebase
class SearchForUsersViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
var results = [Contact]()
var filteredData = [Contact]()
var isSearching = false;
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self;
searchBar.returnKeyType = UIReturnKeyType.done
getUserList()
}
#IBAction func dismiss(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
func getUserList(){
//populates results
staticValuesForData.instance.dataBaseUserref.observe( .value) { (snapshot) in
if let userList = snapshot.children.allObjects as? [DataSnapshot]{
for user in userList{
let name = (user.childSnapshot(forPath: staticValuesForData.instance.fName).value as! String) + " "
+ (user.childSnapshot(forPath: staticValuesForData.instance.lname).value as! String)
let contact = Contact(name: name , uid: user.key,
pic: user.childSnapshot(forPath: staticValuesForData.instance.profileUrl).value as! String,
userName: user.childSnapshot(forPath: staticValuesForData.instance.userName).value as! String )
print(contact.name)
print("user" , user)
self.results.append(contact)
}
}
}
}
}
table view extension :
extension SearchForUsersViewController : UITableViewDataSource ,
UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching{
return results.count
}
return 0;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell" , for: indexPath) as! AddedMeTableViewCell;
cell.profilePicture.loadImageUsingCacheWithUrlString(urlString: filteredData[indexPath.item].picUrl)
if isSearching{
cell.userName.text = filteredData[indexPath.item].userName!
}
else
{
cell.userName.text = results[indexPath.item].userName!
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80;
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
Search extension (where the issue is )
extension SearchForUsersViewController : UISearchBarDelegate{
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == "" || searchBar.text == nil{
view.endEditing(true)
isSearching = false;
tableView.reloadData()
}
else{
isSearching = true
ifSearchContains(word: searchBar.text!)
tableView.reloadData()
print(filteredData)
print(results)
print(searchBar.text)
}
}
func ifSearchContains(word : String)
{
for result in results{
if result.name.contains(word){
filteredData.append(result)
}else{
}
}
}
}
I have the search function above but it is not filtering , nor is the idea of it very efficient. this application is going to have thousands of users, can you please help me filter a search in an efficient way? Thank you so much
Here is the contact custom object just in case
import Foundation
class Contact : NSObject , Comparable{
let name : String!
let uid : String!
let picUrl : String!
let userName : String!
init(name : String , uid : String , pic : String , userName : String) {
self.name = name
self.uid = uid
self.picUrl = pic
self.userName = userName
}
static func ==(lhs: Contact, rhs: Contact) -> Bool {
return lhs.name == rhs.name
}
static func <(lhs: Contact, rhs: Contact) -> Bool {
return lhs.name < rhs.name
}
}

How to pull users from database and list them in a table view using firebase?

I'm using firebase to make an iOS app. I want to retrieve all the users on my database and display their name and profile picture in a table view. Here is my code for my TableViewCell:
import UIKit
import FirebaseDatabase
import FirebaseAuth
import SDWebImage
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var likeImageView: UIImageView!
#IBOutlet weak var messageImageView: UIImageView!
#IBOutlet weak var likeCountButton: UIButton!
var homeVC: HomeViewController?
var postReference: DatabaseReference!
var post: UserFile?{
didSet {
updateView()
}
}
var user: UserFile? {
didSet {
updateUserInfo()
}
}
override func awakeFromNib() {
super.awakeFromNib()
nameLabel.text = ""
let berryTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleLikeTap))
likeImageView.addGestureRecognizer(berryTapGesture)
likeImageView.isUserInteractionEnabled = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func updateView() {
if let photoURL = post?.picURL {
profileImageView.sd_setImage(with: URL(string: photoURL))
}
API.Post.REF_POSTS.child(post!.id!).observeSingleEvent(of: .value, with: { postSnapshot in
if let postDictionary = postSnapshot.value as? [String:Any] {
let post = UserFile.transformPost(postDictionary: postDictionary, key: postSnapshot.key)
self.updateLike(post: post)
}
})
API.Post.REF_POSTS.child(post!.id!).observe(.childChanged, with: { snapshot in
if let value = snapshot.value as? Int {
self.likeCountButton.setTitle("\(value) berries", for: .normal)
}
})
}
func updateLike(post: UserFile) {
let imageName = post.berries == nil || !post.isBerried! ? "berry" : "berrySelected"
likeImageView.image = UIImage(named: imageName)
// display a message for berries
guard let count = post.berryCount else {
return
}
if count != 0 {
likeCountButton.setTitle("\(count) berries", for: .normal)
} else if post.berryCount == 0 {
likeCountButton.setTitle("Be the first to Like this", for: .normal)
}
}
func incrementberries(forReference ref: DatabaseReference) {
ref.runTransactionBlock({ (currentData: MutableData) -> TransactionResult in
if var post = currentData.value as? [String : AnyObject], let uid = Auth.auth().currentUser?.uid {
var berries: Dictionary<String, Bool>
berries = post["berries"] as? [String : Bool] ?? [:]
var likeCount = post["berryCount"] as? Int ?? 0
if let _ = berries[uid] {
// Unlike the post and remove self from stars
likeCount -= 1
berries.removeValue(forKey: uid)
} else {
// Like the post and add self to stars
likeCount += 1
berries[uid] = true
}
post["berryCount"] = likeCount as AnyObject?
post["berries"] = berries as AnyObject?
currentData.value = post
return TransactionResult.success(withValue: currentData)
}
return TransactionResult.success(withValue: currentData)
}) { (error, committed, snapshot) in
if let error = error {
print(error.localizedDescription)
}
if let postDictionary = snapshot?.value as? [String:Any] {
let post = UserFile.transformPost(postDictionary: postDictionary, key: snapshot!.key)
self.updateLike(post: post)
}
}
}
func handleLikeTap() {
postReference = API.Post.REF_POSTS.child(post!.id!)
incrementberries(forReference: postReference)
}
override func prepareForReuse() {
super.prepareForReuse()
profileImageView.image = UIImage(named: "industribune-default-no-profile-pic")
}
func updateUserInfo() {
nameLabel.text = user?.username
if let photoURL = user?.profileImageURL {
profileImageView.sd_setImage(with: URL(string: photoURL), placeholderImage: UIImage(named: "industribune-default-no-profile-pic"))
}
}
}
I am displaying this cell on my HomeViewController:
import UIKit
import FirebaseAuth
import FirebaseDatabase
import FirebaseStorage
import Firebase
class HomeViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
var posts = [UserFile]()
var users = [UserFile]()
override func viewDidLoad() {
super.viewDidLoad()
// for performance set an estimated row height
tableView.estimatedRowHeight = 1
// but also request to dynamically adjust to content using AutoLayout
tableView.rowHeight = UITableViewAutomaticDimension
//tableView.delegate = self
tableView.dataSource = self
loadPosts()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadPosts() {
activityIndicatorView.startAnimating()
API.User.observePosts { (newPost) in
guard let userID = newPost.uid else { return }
self.fetchUser(uid: userID, completed: {
// append the new Post and Reload after the user
// has been cached
self.posts.append(newPost)
self.activityIndicatorView.stopAnimating()
self.tableView.reloadData()
})
}
}
func fetchUser(uid: String, completed: #escaping () -> Void) {
API.User.observeUser(withID: uid) { user in
self.users.append(user)
completed()
}
}
}
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
cell.post = posts[indexPath.row]
cell.user = users[indexPath.row]
cell.homeVC = self
return cell
}
}
I have a lot of craziness going on in my project so let me know if you have any questions and what I'm doing wrong. If it's too complicated to understand I'm ready to erase everything and start over too.
And I do honestly think that I followed all the guidelines to ask a question so don't like shut this question down or something.
That's a lot of code. Try this super reduced example. For this, the users node only stores the name as a child node but it could also have an image, email, address, etc.
Example users node
users
uid_0:
name: "Bert"
uid_1:
name: "Ernie"
and some code
var usersArray = [ [String: Any] ]() //an array of dictionaries.
class ViewController: UIViewController {
//set up firebase references here
override func viewDidLoad() {
super.viewDidLoad()
let usersRef = self.ref.child("users")
usersRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let userDict = snap.value as! [String: Any]
self.usersArray.append(userDict)
}
self.tableView.reloadData()
})
and the tableView delegate methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.usersArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
let userDict = self.usersArray[indexPath.row]
cell.text = userDict["name"] as! String
//cell.imge = userDict["image"] etc etc
return cell
}
Now... that all being said. This is the perfect use for an array of UserClass objects instead of the dictionaries.
Here's a starting point....
class UserClass {
var name = ""
var image = ""
func init(snap: DataSnapshot) {
//populate the vars from the snapshot
}
}
var userClassArray = [UserClass]()
Don't copy and paste this as there are probably typos but it should point you in the right direction.

tableview: cellForRowAtIndexPath is not being called

I can't figure out what is wrong with my tableView: cellForRowAtIndexPath. its never getting called for some reason. i have called the proper delegate and datasource. When I add a print("") line under the cellForRowAtIndexPath function, it never appears when i simulate the app.
Thank you in advanced.
here is my code for the whole page:
class MainPageViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var sportCells = [PFObject]()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var profilePictureImageView: UIImageView!
#IBOutlet weak var fullNameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
//Do any additional setup after loading the view.
}
override func viewDidAppear(animated: Bool) {
updateSportsTable()
print("its happening")
let lastName = PFUser.currentUser()! ["last_name"]
if let firstName = PFUser.currentUser()?["first_name"] as? String {
self.fullNameLabel.text = "\(firstName) \(lastName)"
}
if let userPicture = PFUser.currentUser()?["profile_picture"] as? PFFile {
userPicture.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if (error == nil) {
self.profilePictureImageView.image = UIImage(data:imageData!)
}
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("sportCells count is \(sportCells.count)")
return sportCells.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("data extracted1")
let cell = tableView.dequeueReusableCellWithIdentifier("sportCell") as! SportTableViewCell
print("data extracted")
let sportPost = self.sportCells[indexPath.row]
let user = sportPost["user"] as! PFUser
print("data extracted")
do {
try user.fetchIfNeeded()
print("its happening 3rd time")
} catch _ {
print("There was an error")
}
cell.sportTitle.text = sportPost["basketballTitle"] as? String
cell.sportLogo.text = sportPost["basketballLogo"] as? String
cell.numberOfPOTM.text = "5"
return cell
}
func updateSportsTable() {
let query = PFQuery(className: "Sports")
query.findObjectsInBackgroundWithBlock { (sportCells:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.tableView.reloadData()
print("its happening again")
}
}
}
As confirmed from the comments, you problem is data population in model sportCells.
Ensure that sportCells is populated properly and that you call self.tableView.reloadData after that.

Resources