I am trying to retrieve data from firebase and display them in a tableview but my code for some reason is not working. I am getting the images and appending them into a list but that list is not having any data outside the else block.
With my implementation, I am getting a blank tableview. Could someone help with me this please?
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
let db = Firestore.firestore()
var usersReference = Firestore.firestore().collection("users")
var storageReference = Storage.storage().reference()
var imagesList = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
usersReference.addSnapshotListener { [self] (querySnapshot, error) in
querySnapshot?.documents.forEach() {
(document) in
let uid = document.data()["uid"] as! String
let imagePath = "profilePictures/\(uid).jpg"
let imgRef = storageReference.child(imagePath)
imgRef.getData(maxSize: 1 * 2048 * 2048) { data, error in
if let error = error {
print(String(describing: error))
}
else {
DispatchQueue.main.async {
let image = UIImage(data: data!)
imagesList.append(image!)
print("inside viewDidLoad: ", imagesList.count)
}
}
}
}
}
print(imagesList.count)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return imagesList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath)
print("cellForRowAt: ",imagesList.count)
cell.textLabel?.text = "\(indexPath.row)"
cell.imageView?.image = imagesList[indexPath.row]
return cell
}
This is how my simulator looks like when I run the code: compiled code .
Related
I'm trying to save collection into an array of objects called List, and the retrieving is been called in viewdidload by the function loadfirebase. So it actually retrieves the data from firebase and prints it but it doesn't save it in the array. I think it is something that deals with closure but not sure how to fix it.
//
// ContactList.swift
// Socket
//
// Created by dalal aljassem on 12/16/21.
//
import UIKit
import FirebaseFirestore
import FirebaseStorage
class ContactList: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let storage = Storage.storage().reference()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return List.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell" , for:indexPath)
var currentname = List[indexPath.row]
cell.textLabel?.text = currentname.name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
print("some action will happen when i tap here")
}
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadfirebase()
print("**************",List)
}
}
let database = Firestore.firestore()
func loadfirebase()
{
let contactdataRef = database.collection("ContactData")
contactdataRef.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
// var currentDoc = document.data()
print("///////////////")
// print("current doc = " , currentDoc)
print("current name = " , document.get("name")!)
print("current image = " , document.get("image")!)
List.append(Contact(name: document.get("name") as! String, image: document.get("image") as! String, number: ""))
print("\(document.documentID) => \(document.data())")
}
}
}}
}
Your List array is never initialized.
You can achieve this with the following code:
var List: [Contact] = []
and I would put this before the declaration of tableView function.
As shown below I want to sort my TableViewCells by the date. For this I have the time which is also called timestampName.
Right before I reload the data, I tried to sort it, but somehow this has no effect. It also throws me a warning, that I dont use the result of the sorted by. I understand this, but I dont know how to fix that.
import UIKit
import Firebase
class popularViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet var table: UITableView!
// var models = [PhotoPost]()
var texttt = [TextPost]()
override func viewDidLoad() {
super.viewDidLoad()
gettingPosts()
table.register(popularTableViewCell.nib(), forCellReuseIdentifier: popularTableViewCell.identifier)
table.register(featuredTableViewCell.nib(), forCellReuseIdentifier: featuredTableViewCell.identifier)
table.register(textTableViewCell.nib(), forCellReuseIdentifier: textTableViewCell.identifier)
table.delegate = self
table.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return texttt.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: self.texttt[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 300
}
func gettingPosts(){
let db = Firestore.firestore()
let postsRef = db.collection("posts")
postsRef.addSnapshotListener { (querySnapshot, error) in
guard let snapshot = querySnapshot else {
print("Error fetching snapshots: \(error!)")
return
}
snapshot.documentChanges.forEach { diff in
if (diff.type == .added){
let data = diff.document.data()
let Name = data["username"] as! String
let text = data["description"] as! String
let likes = data["likes"] as! Int
let typ = data["postType"] as! Int
let pfp = data["profileImage"] as! String
let uid = data["uid"] as! String
let pic = data["picture"]
let time = data["time"] as! String
if typ == 0{ // Text post
let dasDing = TextPost(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text)
self.texttt.append(dasDing)
self.texttt.sorted(by: { $0.timestampName < $1.timestampName }) //WARNING: Result of call to 'sorted(by:)' is unused
self.table.reloadData()
}
struct TextPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
}
Use sort instead of sorted. The sorted method returns a new sorted array, on the other hand, the sort method sorts the array on which it was called.
self.texttt.sort(by: { $0.timestampName < $1.timestampName })
This should also work, using sorted:
self.texttt = self.texttt.sorted(by: { $0.timestampName < $1.timestampName })
I saved the photo and name of the movie to CoreData. entity name is movieEntity
When I try to show a photo and name of a movie in tableView, I have a problem with the picture. The name of the movie successfully visible to tableView, but the photo of the movie is not visible.
class movieViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var movie: [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "movieEntity")
do {
coreDataMoviePhoto = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
}
extension movieViewController: UITableViewDataSource, UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movie.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let movieData = movie[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "movieTableViewCell", for: indexPath) as! movieTableViewCell
cell.tableViewCellImageView.image = movieData.value(forKeyPath: "img") as? UIImage
cell.tableViewTextLabel.text = movieData.value(forKeyPath: "name") as? String
return cell
}
}
here is movieTableViewCell
class CoreDataWatchlistTableViewCell: UITableViewCell {
#IBOutlet weak var tableViewTextLabel: UILabel!
#IBOutlet weak var tableViewCellImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
}
As you saving image data not image in so use
if let data = movieData.value(forKeyPath: "img") as? Data{
cell.tableViewCellImageView.image = UIImage(data:data)
}else{
cell.tableViewCellImageView.image = somePlaceholderImage
}
hope its help
I cannot understand why the cells do not resize according to the given .xib file
This is my table controller
import Foundation
import UIKit
class RecipeTableView: UIViewController {
let cellIdentifier = "RecipeTableViewCell"
#IBOutlet weak var recipeTableView: UITableView!
private let localDatabaseManager: LocalDatabaseManager = LocalDatabaseManager.shared
private var recipes = [Recipe]()
override func viewDidLoad() {
super.viewDidLoad()
recipeTableView.dataSource = self
recipeTableView.delegate = self
//recipeTableView.rowHeight = UITableView.automaticDimension
//recipeTableView.estimatedRowHeight = UITableView.automaticDimension
self.recipeTableView.register(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
localDatabaseManager.loadRecipes { [weak self] (recipes) in
guard let recipes = recipes else {
return
}
self?.recipes = recipes
DispatchQueue.main.async {
self?.recipeTableView.reloadData()
}
}
}
// override func viewWillAppear(_ animated: Bool) {
// recipeTableView.estimatedRowHeight = 256
// recipeTableView.rowHeight = UITableView.automaticDimension
// }
}
extension RecipeTableView: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
recipes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? RecipeTableViewCell else {
return UITableViewCell()
}
let recipe = recipes[indexPath.row]
cell.configure(with: recipe)
//cell.layer.cornerRadius = 32
//cell.layer.masksToBounds = true
return cell
}
}
extension RecipeTableView: UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}
And my cell swift file
import Foundation
import UIKit
import Kingfisher
import Cosmos
class RecipeTableViewCell: UITableViewCell {
#IBOutlet weak var recipeNameLabel: UILabel!
#IBOutlet weak var recipeDescriptionLabel: UILabel!
#IBOutlet weak var recipeImageView: UIImageView!
#IBOutlet weak var recipeCosmosView: CosmosView!
override func prepareForReuse() {
super.prepareForReuse()
recipeNameLabel.text = nil
recipeDescriptionLabel.text = nil
recipeImageView.image = nil
}
func configure(with recipe: Recipe) {
recipeNameLabel?.text = recipe.name
recipeDescriptionLabel?.text = recipe.description
//let imageBytes = recipe.imageData
//let imageData = NSData(bytes: imageBytes, length: imageBytes.count)
//let image = UIImage(data: imageData as Data)
//recipeImageView?.image = image
let imageUrl = URL(string: recipe.imageData)
recipeImageView?.kf.setImage(with: imageUrl)
recipeCosmosView.settings.fillMode = .precise
recipeCosmosView.rating = recipe.rating
}
}
here is what my custom cell looks like
here is how these cells are shown in the app
I already found similar questions, but everywhere the same answer. Need to add the following lines. So I tried.
override func viewWillAppear(_ animated: Bool) {
recipeTableView.estimatedRowHeight = 256
recipeTableView.rowHeight = UITableView.automaticDimension
}
But it did not work
I think you need to call another tableView method for set the height for each cell according to his content
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// add estimated height here ....
//...
return indexPath.row * 20
}
Very big thanks in advance to anyone who can help me, very much appreciated!
I am building a dating app and I am trying to have my matches load in a table after a parse query. The expected result is that the table view contains the match image and the match ID. Right now I have code for that working perfectly below.
import UIKit
import Parse
class MyListViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
var images = [UIImage]()
var userIds = [String]()
#IBOutlet weak var tView: UITableView!
#IBAction func toSwiperButton(_ sender: Any) {
performSegue(withIdentifier: "ToSwiper", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
let query = PFUser.query()
query?.whereKey("objectId", containedIn: PFUser.current()?["accepted"]
as! [String])
query?.findObjectsInBackground(block: { (objects, error) in
if let users = objects {
for object in users {
if let user = object as? PFUser {
let imageFile = user["photo"] as! PFFile
imageFile.getDataInBackground(block: { (data, error) in
if let imageData = data {
self.images.append(UIImage(data: imageData)!)
self.userIds.append(user.objectId!)
self.tView.reloadData()
}
})
}
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return images.count
}
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PDPLIstViewTableViewCell
cell.Image.image = images[indexPath.row]
cell.id.text = userIds[indexPath.row]
return cell
}
}
The problem arises when I try to include two additional labels onto the table view for "name" and for "age" - I cant seem to figure the correct way to call them in the query in Parse along with the working photo query.
The result I want is for every cell in the table to have an image (code is working) Id (code is working) Name (code not working) and age (code not working)
By "not working" what I mean is I get a ton of errors when I try o create the variable for age from the parse data so I can pass it into the array so that my tableview can display the text next to the image.
Here is what I have been using for non working code on the "Age" label, I believe the error is where I am trying to pull the name/age using "= data" and I have to use a different term?
import UIKit
import Parse
class MyListViewController: UIViewController, UITableViewDataSource,
UITableViewDelegate {
var images = [UIImage]()
var userIds = [String]()
var name = [String]()
var age = [String]()
#IBOutlet weak var tView: UITableView!
#IBAction func toSwiperButton(_ sender: Any) {
performSegue(withIdentifier: "ToSwiper", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
let query = PFUser.query()
query?.whereKey("objectId", containedIn: PFUser.current()?["accepted"]
as! [String])
query?.findObjectsInBackground(block: { (objects, error) in
if let users = objects {
for object in users {
if let user = object as? PFUser {
let ageFile = user["age"] as! PFFile
ageFile.getDataInBackground(block: { (data, error) in
if let ageData = data {
self.age.append(UILabel(data: ageData)!)
}
let imageFile = user["photo"] as! PFFile
imageFile.getDataInBackground(block: { (data, error) in
if let imageData = data {
self.images.append(UIImage(data: imageData)!)
self.userIds.append(user.objectId!)
self.age.append(String(data: ageFile))
self.tView.reloadData()
}
})
}
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return images.count
}
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for:
indexPath) as! PDPLIstViewTableViewCell
cell.image.image = images[indexPath.row]
cell.id.text = userIds[indexPath.row]
cell.name.text = name[indexPath.row]
cell.age.text = age[indexPath.row]
return cell
}
}
You are reloading the tableview in the loop (a lot), also you do not reload when ageData is complete. Try reloading the tableview once, once the query is done. In the:
internal func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
guard let ageFile = age[indexPath.row] as? PFFile else { return }
ageFile.getDataInBackground(block: { (data, error) in
if let ageData = data {
cell.age.text = ageData
}
}