Display pictures in a TableView from Firebase Storage in SWIFT without mistake - ios

I have a chat app where people can talk in a group and a little picture is displayed in each cell to show who is talking. I managed to display these pictures from Firebase storage but it is not always the right picture which is displayed at the right place.
It only works when I go to the previous View Controller and coming back the chat View to see the pictures displayed properly in each cell.
I tried override prepareForReuse() but it's not better. Do you have any idea how I could solve this problem ?
import UIKit
class CustomMessageCell: UITableViewCell {
#IBOutlet weak var messageBody: UILabel!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var messageBubble : UIView!
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var messageBodyTextView: UITextView!
#IBOutlet weak var userPicture: UIImageView!
#IBOutlet weak var imageButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
messageBubble.layer.cornerRadius = messageBubble.frame.size.height / 5
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
super.prepareForReuse()
userPicture.image = nil
messageBodyTextView.text = ""
usernameLabel.text = ""
timeLabel.text = ""
print("prepareforreuse")
}
}
for the class ConversationViewController
class ConversationViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, UNUserNotificationCenterDelegate, GADBannerViewDelegate {
// ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let message = messageArray[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "customMessageCell", for: indexPath) as! CustomMessageCell
cell.userPicture.image = nil
cell.selectionStyle = .none
//...
cell.messageBodyTextView.text = messageArray[indexPath.row].messageBody
cell.usernameLabel.text = messageArray[indexPath.row].name
cell.timeLabel.text = dateToShow
cell.userPicture.layer.cornerRadius = cell.userPicture.frame.height / 2
cell.userPicture.clipsToBounds = true
// Charge image
let imagePath = self.storageRef.reference(withPath:"\(message.uid)/resizes/profilImage_150x150.jpg")
imagePath.getData(maxSize: 10 * 1024 * 1024) { (data, error) in
if let error = error {
cell.userPicture.image = UIImage(named: "emptyProfilPic")
print("Got an error fetching data : \(error.localizedDescription)")
// return
}
if let data = data {
cell.userPicture.image = UIImage(data: data)
}
}
return cell
}
}

Related

Table View Cell has no Initialiser

I am trying to display table view cell property into different table view cell when button I clicked . I am using story board . I added the Horizontal and vertical stack to contains the image and label properties . I want to display this property into another table view cell when user clicked the show button . In cellFor row function i defined the button action property . I am getting following error .Class 'DetailsViewCell' has no initializers. Cannot use instance member 'mc' within property initializer; property initializers run before 'self' is available
Here is the screenshot of the both view controller .
Here is the code .
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// guard let cell = tableView.dequeueReusableCell(withIdentifier: MovieCell.identifier, for: indexPath) as? MovieCell
// else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
cell.showButton.tag = indexPath.row
cell.showButton.addTarget(self, action: Selector("movieDetails"), for: .touchUpInside)
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
}
Here is the code in identifier class with table view cell.
class MovieViewCell: UITableViewCell {
static let identifier = "MovieViewCell"
#IBOutlet weak var mainStackView: UIStackView!
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTtile: UILabel!
#IBOutlet weak var movieOverview: UILabel!
#IBOutlet weak var showButton: UIButton!
#IBAction func movieDetails(_ sender: UIButton) {
var dc : DetailsViewCell
movieTtile = dc.movieTitle
movieOverview = dc.movieOverview
movieImage = dc.movieImage
}
func configureCell(title: String?, overview: String?, data: Data?) {
movieTtile.text = title
movieOverview.text = overview
if let imageData = data{
movieImage.image = UIImage(data: imageData)
}
}
}
Here is the code for Details view cell.
class DetailsViewCell: UITableViewCell {
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
#IBOutlet weak var movieImage: UIImageView!
var mc : MovieViewCell
movieTitle = mc.movieTtile
movieOverview = mc.movieOverview
movieImage = mc.movieImage
}
import UIKit
var loginData = ["", "", ""]
class LoginDataCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var txtLoginData: 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
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField.tag == 0 {
loginData[0] = textField.text
} else if textField.tag == 1 {
loginData[1] = textField.text
} else if textField.tag == 2 {
loginData[2] = textField.text
}
}
}

How to copy a String by pressing a button inside UITableView Cell in Swift

I have an array of data "electricity" which I am getting from the server. I have a button inside a UITableView Cell name "copyPinButton". Inside 'cellForRowAt indexPath' I am placing the data necessarily. I want to copy a string value that I am getting from the server by pressing 'copyPinButton'. Thanks in advance.
import UIKit
class ElectricityBillTransactionHistoryViewController: BaseViewController {
#IBOutlet weak var electricityTransactionHistoryTableView: UITableView!
private var electricity = [Electricity]()
override func viewDidLoad() {
super.viewDidLoad()
electricityTransactionHistoryTableView.delegate = self
electricityTransactionHistoryTableView.dataSource = self
electricityTransactionHistory()
}
func electricityTransactionHistory() {
webserviceHandler.transactionHIstory(onCompletion: { (TransactionHistoryResponse) in
if TransactionHistoryResponse.code == 200 {
self.electricity = TransactionHistoryResponse.data?.electricity ?? []
self.electricityTransactionHistoryTableView.delegate = self
self.electricityTransactionHistoryTableView.dataSource = self
self.electricityTransactionHistoryTableView.reloadData()
}else {
self.showDialog(title: nil, message: TransactionHistoryResponse.message ?? K.Messages.DefaultErrorMessage, onDefaultActionButtonTap: nil)
}
}, onFailure: { ( _) in
self.showDialog(title: nil, message: K.Messages.DefaultErrorMessage, onDefaultActionButtonTap: nil)
}, shouldShowLoader: true)
}
}
extension ElectricityBillTransactionHistoryViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return electricity.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "electricityTransactionHistoryTableViewCellId", for: indexPath) as! electricityTransactionHistoryTableViewCell
let electricityData = electricity[indexPath.row]
cell.electricityBillHistoryTitleLabel.text = electricityData.packName
cell.electricityBillTransactionIdLabel.text = "\( electricityData.trackerID ?? 0)"
cell.electricityBillAmountLabel.text = "\(electricityData.paidAmount ?? 0)"
cell.electricityBillPaymentDateLabel.text = Util.getFormattedDateString(inputDateString: electricityData.purchasedDate ?? "", inputDateFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ", outputDateFormat: "dd MMM yyyy - h:mm a")
return cell
}
}
class electricityTransactionHistoryTableViewCell: UITableViewCell {
#IBOutlet weak var electricityBillContainerView: UIView!
#IBOutlet weak var copyPinButton: UIButton!
#IBOutlet weak var electricityBillImageView: UIImageView!
#IBOutlet weak var electricityBillHistoryTitleLabel: UILabel!
#IBOutlet weak var electricityBillAmountLabel: UILabel!
#IBOutlet weak var electricityBillMonthLabel: UILabel!
#IBOutlet weak var electricityBillTransactionIdLabel: UILabel!
#IBOutlet weak var electricityBillPaymentDateLabel: UILabel!
override func awakeFromNib() {
copyPinButton.layer.masksToBounds = false
copyPinButton.layer.shadowColor = UIColor.gray.cgColor
copyPinButton.layer.shadowOpacity = 0.5
copyPinButton.layer.shadowOffset = CGSize(width: 1.5, height: 0.5)
copyPinButton.layer.shadowRadius = 3
electricityBillContainerView.layer.masksToBounds = false
electricityBillContainerView.layer.shadowColor = UIColor.gray.cgColor
electricityBillContainerView.layer.shadowOpacity = 0.5
electricityBillContainerView.layer.shadowOffset = CGSize(width: 2.0, height: 0.5)
electricityBillContainerView.layer.shadowRadius = 3
}
#IBAction func copyButtonTapped(_ sender: Any) {
}
}
Use UIPasteboard directly
// write to clipboard
UIPasteboard.general.string = "Hello world"
// read from clipboard
let content = UIPasteboard.general.string
Check this question for more detailed answers
You can copy text or string using UIPasteboard like below:
#IBAction func copyButtonTapped(_ sender: Any) {
UIPasteboard.general.string = "Your value"
}

How to implement event on click in button inside in a tableView to show other element?

I have a tableView with action buttons, one of them are hide until the user click the other button, I was looking how to do that and I found that I have to implement a delegate like the code below:
Class TableViewCell:
import UIKit
import FLAnimatedImage
protocol OnButtonsClickDelegate:AnyObject{
func onBtnDownloadClick(cell: ListadoTableViewCell)
}
class ListadoTableViewCell: UITableViewCell {
#IBOutlet weak var lblAnterior: UILabel!
#IBOutlet weak var lblCompras: UILabel!
#IBOutlet weak var lblDevolucion: UILabel!
#IBOutlet weak var lblSaldo: UILabel!
#IBOutlet weak var lblAbonos: UILabel!
#IBOutlet weak var lblNuevo: UILabel!
#IBOutlet weak var lblDiferido: UILabel!
#IBOutlet weak var lblCliente: UILabel!
#IBOutlet weak var lblNombreCliente: UILabel!
#IBOutlet weak var spinner: FLAnimatedImageView!
#IBOutlet weak var btnDowload: UIButton!
#IBOutlet weak var btnShare: UIButton!
var onButtonsClickDelegate : OnButtonsClickDelegate!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBAction func onBtnDownloadClick(_ sender: AnyObject){
onButtonsClickDelegate.onBtnDownloadClick(cell: self)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Class Controller:
class ListadoController: NavigationViewController, UITableViewDelegate, UITableViewDataSource, RefreshScrollViewDelegate,OnButtonsClickDelegate {
#IBOutlet weak var tableView: RefreshTableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellListado") as! ListadoTableViewCell
let r = data[indexPath.row]
let compras = Functions.stringToFloat(str: r.compras)
let comprasn = Functions.stringToFloat(str: r.comprasn)
let abonos = Functions.stringToFloat(str: r.abonos)
let diferido = Functions.stringToFloat(str: r.diferido)
let saldomov = Functions.stringToFloat(str: r.saldomov)
cell.lblAnterior.text = Functions.moneyFormat(n: saldomov - compras - comprasn)
cell.lblCompras.text = Functions.moneyFormat(n: compras)
cell.lblDevolucion.text = Functions.moneyFormat(n: 0.0)
cell.lblSaldo.text = Functions.moneyFormat(n: saldomov - comprasn)
cell.lblAbonos.text = Functions.moneyFormat(n: abonos) + ""
cell.lblNuevo.text = Functions.moneyFormat(n: saldomov - comprasn - abonos) + ""
cell.lblDiferido.text = Functions.moneyFormat(n: diferido) + ""
cell.lblCliente.text = r.nombre.capitalized
cell.lblNombreCliente.text = r.cvecte
cell.onButtonsClickDelegate = self
if indexPath.row == data.count - 1 {
if (!last && !loading) {
loadData(page: currentPage)
}
}
return cell
}
func onBtnDownloadClick(cell: ListadoTableViewCell) {
cell.btnShare.isHidden = false
}
}
The problem is that it does not work correctly. When the user clicks the button, the other element is displayed but not only in the selected row, but also in other rows as well, how can I solve this problem?
The cell is being re-used and whatever is the state of that cell will still be there, in which case, try adding this to ListadoTableViewCell:
override func prepareForReuse() {
super.prepareForReuse()
btnShare.isHidden = true
}
You should try to save the state of the cell when you press the download button so that when the reloadData of the TableView is performed and the cellForRowAt function is called, the state of the changes in the cells is preserved, in your case the share button is shown if the download button has previously been pressed.
Here there is a project from my Github that make the functionality you need by applying MVVM Pattern https://github.com/JLPenaLopez/MyFiles I hope this helps you
This is a demostration: https://github.com/JLPenaLopez/MyFiles/blob/master/MyFilesGif.gif
I solved using an answer from another post:
Button action in custom UITableViewCell affects other cells
Thank you for your help.

Having trouble connecting my CustomCell.xib to my tableView in the storyboard

I Have to do an app for recipes and it shows me different recipes in my tableView, and i just want to implement my CustomCell (from a xib file) to my storyboard and I don't know how to connect it to show my data (I already checked my identifier) here's the code of my controller :
class SearchRecipe: UIViewController, ShowAlert {
var recipeData = RecipeDataModel()
var recipe = [String]()
#IBOutlet weak var tableViewSearch: UITableView!
override func viewDidLoad() {
self.tableViewSearch.rowHeight = 130
}
func updateRecipeData(json: JSON){
if let ingredients = json["hits"][0]["recipe"]["ingredientLines"].arrayObject{
recipeData.ingredientsOfRecipe = ingredients[0] as! String
recipeData.cookingTime = json["hits"][0]["recipe"]["totalTime"].stringValue
recipeData.recipe = json["hits"][0]["recipe"]["label"].stringValue
recipeData.recipeImage = json["hits"][0]["recipe"]["image"].stringValue
}
else {
print("Problem")
}
//self.tableViewSearch.reloadData()
}
}
extension SearchRecipe: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipe.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customRecipeCell", for: indexPath) as! CustomRecipeCell
getRecipesDisplay(in: cell, from: recipeData , at: indexPath)
return cell
}
func getRecipesDisplay(in cell: CustomRecipeCell, from recipeModel: RecipeDataModel, at indexPath: IndexPath){
cell.recipeTitle.text = recipeData.recipe
cell.recipeInfos.text = recipeData.ingredientsOfRecipe
cell.timerLabel.text = recipeData.cookingTime
}
}
and this is the code my xib file :
class CustomRecipeCell: UITableViewCell {
#IBOutlet weak var recipeTitle: UILabel!
#IBOutlet weak var recipeInfos: UILabel!
#IBOutlet weak var cellImageBackground: UIImageView!
#IBOutlet weak var likeAndTimerView: UIView!
#IBOutlet weak var likeImage: UIImageView!
#IBOutlet weak var timerImage: UIImageView!
#IBOutlet weak var likeLabel: UILabel!
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
override func awakeFromNib() {
super.awakeFromNib()
activityIndicator.isHidden = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
In ViewDidLoad, you must register your cell this way:
override func viewDidLoad() {
tableViewSearch.register(UINib(nibName:" /* NAME OF YOUR XIB FILE */ ", bundle: nil), forCellReuseIdentifier: "customRecipeCell")
}
You also have to edit the size of your cell in the attribute inspector of your custom cell and of your table view

Custom UITableViewCell doesn't show all contents

My problem is that I have a custom cell that doesn't show all the contents showed in the storyboard.
cellForRowAt code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "menuCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? MenuTableCell
cell?.accessoryType = .disclosureIndicator;
cell?.altriPiattiLabel.isHidden = true
cell?.piatto3Label.isHidden = true
cell?.sceltaMiglioreLabel.isHidden = true
cell?.numeroMenuLabel.text = "MenĂ¹ \(indexPath.row+1)"
cell?.numeroPiattiLabel.text = "\(menus[indexPath.row].getPiatti().count) piatti"
cell?.piatto1Label.text = "Piatto 1: \(menus[indexPath.row].getPiatti()[0].getDescrizione())"
cell?.piatto2Label.text = "Piatto 2: \(menus[indexPath.row].getPiatti()[1].getDescrizione())"
if (menus[indexPath.row].getPiatti().count >= 3) {
cell?.piatto3Label.isHidden = false
if(menus[indexPath.row].getPiatti().count > 3) {
cell?.altriPiattiLabel.isHidden = false
}
print("heeeeere")
cell?.piatto3Label.text = "Piatto 3: \(menus[indexPath.row].getPiatti()[2].getDescrizione())"
}
if(indexPath.row == 0) {
cell?.sceltaMiglioreLabel.isHidden = false
}
if(indexPath.row == menus.count-1) {
cell?.sceltaMiglioreLabel.isHidden = false
cell?.sceltaMiglioreLabel.text = "scelta peggiore"
cell?.sceltaMiglioreLabel.backgroundColor = UIColor.red
}
return cell!
}
Custom cell code:
import UIKit
class MenuTableCell: UITableViewCell {
#IBOutlet weak var numeroMenuLabel: UILabel!
#IBOutlet weak var sceltaMiglioreLabel: UITextView!
#IBOutlet weak var piatto1Label: UILabel!
#IBOutlet weak var piatto2Label: UILabel!
#IBOutlet weak var piatto3Label: UILabel!
#IBOutlet weak var cliccaPerInfoLabel: UILabel!
#IBOutlet weak var numeroPiattiLabel: UILabel!
#IBOutlet weak var altriPiattiLabel: UILabel!
override func layoutSubviews() {
sceltaMiglioreLabel.layer.masksToBounds = true;
sceltaMiglioreLabel.layer.cornerRadius = 10.0
altriPiattiLabel.layer.masksToBounds = true;
altriPiattiLabel.layer.cornerRadius = 10.0
}
override func awakeFromNib() { super.awakeFromNib() }
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Storyboard settings:
My cell settings in the storyboard
"sceltaMiglioreLabel" and the disclosureIndicator are never showed up in the simulator.
Thanks in advance.

Resources