Dynamically resize TableViewCell with and with out images - ios

Using swift3, I want to allow users to create posts of either pictures or simple text posts. I have everything working fine except for when I create a post of just text, the UIImageView in the cell fills out space in the TableViewCell. Ideally, if the user creates a post of just text, the TableViewCell will only include everything down to the caption label but not the UIImageView (see image). How can I go about this.
Research: https://www.youtube.com/watch?v=zAWO9rldyUE,
https://www.youtube.com/watch?v=TEMUOaamcDA, https://www.raywenderlich.com/129059/self-sizing-table-view-cells
Current Code
func configureCell(post: Post){
self.post = post
likesRef = FriendSystem.system.CURRENT_USER_REF.child("likes").child(post.postID)
userRef = FriendSystem.system.USER_REF.child(post.userID).child("profile")
self.captionText.text = post.caption
self.likesLbl.text = "\(post.likes)"
self.endDate = Date(timeIntervalSince1970: TimeInterval(post.time))
userRef.observeSingleEvent(of: .value, with: { (snapshot) in
let snap = snapshot.value as? Dictionary<String, Any>
self.currentUser = MainUser(uid: post.userID, userData: snap!)
self.userNameLbl.text = self.currentUser.username
if let profileImg = self.currentUser.profileImage {
self.profileImg.loadImageUsingCache(urlString: profileImg)
} else {
self.profileImg.image = #imageLiteral(resourceName: "requests_icon")
}
})
// This is where I belive I need to determine wether or not the cell should have an image or not.
if let postImg = post.imageUrl {
self.postImg.loadImageUsingCache(urlString: postImg)
}

I see you're using storyboard to create your UI, in that case you can add a height constraint to your UIImageView (make sure to connect it your cell in order to use it in code) and change the constraint and the height of your tableview when required.
class MyCell: UITableViewCell {
#IBOutlet var postImage: UIImageView!
#IBOutlet var postImageHeight: NSLayoutConstraint!
}
class ViewController: UITableViewController {
var dataSource: [Model] = []
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//Cell without image
if dataSource[indexPath.row].image == nil {
return 200
}
//Cell with image
return 350
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
//Adjust the height constraint of the imageview within your cell
if dataSource[indexPath.row].image == nil {
cell.postImageHeight.constant == 0
}else{
cell.postImageHeight.constant == 150
}
return cell
}
}

Related

How to get different image from assets and assign it to image view in different table view cells

I am trying to add an image to my tableview cell by using an NFC reader session. So, my problem here is that every first reader session, I am getting the correct image in image view, but when I try the reader session the second time, I am stuck with two same last assigned image on both cells of my table view. I know it because of tableView.dequeueReusableCell method, but I am not sure which method to use to get correct image incorrect cells.
I have also attached a screenshot to make more clear of what I mean.
In the screenshot is should see an image of a water bottle from my assets, but instead, I am getting the last assigned image to every cell
Here is the code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.nfcModel = arrData[indexPath.row]
// IMG CELL
cell.img.image = UIImage(named: name)
return cell
}
Not an expert in NFC readers.
1.Create an array of products to store product data from NFC render.
2.in tableView func cellForRowAt you can render the images from
favoriteMovies using displayMovieImage function.
Sidenote:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var favoriteMovies: [Movie] = []
override func viewWillAppear(_ animated: Bool) {
mainTableView.reloadData()
super.viewWillAppear(animated)
if favoriteMovies.count == 0 {
favoriteMovies.append(Movie(id: "tt0372784", title: "Batman Begins", year: "2005", imageUrl: "https://images-na.ssl-images-amazon.com/images/M/MV5BNTM3OTc0MzM2OV5BMl5BanBnXkFtZTYwNzUwMTI3._V1_SX300.jpg"))
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let moviecell = tableView.dequeueReusableCell(withIdentifier: "customcell", for: indexPath) as! CustomTableViewCell
let idx: Int = indexPath.row
moviecell.tag = idx
//title
moviecell.movieTitle?.text = favoriteMovies[idx].title
//year
moviecell.movieYear?.text = favoriteMovies[idx].year
// image
displayMovieImage(idx, moviecell: moviecell)
return moviecell
}
func displayMovieImage(_ row: Int, moviecell: CustomTableViewCell) {
let url: String = (URL(string: favoriteMovies[row].imageUrl)?.absoluteString)!
URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async(execute: {
let image = UIImage(data: data!)
moviecell.movieImageView?.image = image
})
}).resume()
}

UITableView load wrong cell height Swift

I'm doing with Xcode 10. I have a tableview in ViewController.
The cell has label which is set as leading, tralling, top and bottom, line is 0
In ViewDidload() I added
override func viewDidLoad() {
super.viewDidLoad()
tableview.rowheight = UITableView.automaticDimension
tableview.estimateheight = 98
tableview.reloaddata()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) as! CommentCell
let idcmt: String
idcmt = self.CommentIDArray[indexPath.row]
ref.child("Post_theme/\(userid!)/\(id)/comment/\(idcmt)").observe( .value, with: {(snapshot) in
let value = snapshot.value as? NSDictionary
cell.Comment.text = value!["content"] as? String
})
// I have a button in the custom cell but tableview load height wrong even I did not click the button on cell
self.ref.child("Post_theme/\(self.userid!)/\(self.id)/comment/\(idcmt)/likecomment").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChild(self.userid!){
cell.Heartcommentaction = {
cell.HeartCommentbutton.tintColor = .lightGray
self.TableCommentView.reloadData()
}
}
})
return cell
}
class CommentCell: UITableViewCell{
var Heartcommentaction : (() -> ()) = {}
#IBOutlet weak var Comment: UILabel!
#IBOutlet weak var HeartCommentbutton: UIButton!
#IBAction func HeartCommentaction(_ sender: Any) {
Heartcommentaction()
}
}
But when I click to Viewcontroller, tableview did not load the right height cell ( cell which is needed to autorize is not, cell which is not needed is resize)
Then I add this code
override func viewDidAppear(_ animated: Bool) {
tableview.reloadData()
}
the code run well just for initial few cells, but when I scroll down more (I have around over 100 cells), it's wrong height again, when I scroll up the initial cells get again wrong
I looked many solutions but not working for me
Really need help! thank you
UPDATE
this is the screenshot of wrong height cell, some timewrong, sometime right
Use :
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 98
}
Also remove tableview.estimateheight = 98
Give this a shot. My code here may not compile because I don't have your full source code. Remember, cellForRow should synchronously set all values on your cell. And you don't want to call reloadData because you will see glitches when scrolling. You want to call reloadRows. See below and see if that helps:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) as! CommentCell
let idcmt: String
idcmt = self.CommentIDArray[indexPath.row]
cell.Comment.text = "..."
cell.Heartcommentaction = {}
ref.child("Post_theme/\(userid!)/\(id)/comment/\(idcmt)")
.observe( .value, with: {(snapshot) in
let value = snapshot.value as? NSDictionary
if let value = value, let indexPath = tableView.indexPath(for: cell) {
cell.Comment.text = value!["content"] as? String
tableView.reloadRows(at: [indexPath], .fade)
} else {
print("nope")
}
})
self.ref.child("Post_theme/\(self.userid!)/\(self.id)/comment/\(idcmt)/likecomment")
.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChild(self.userid!){
if let indexPath = tableView.indexPath(for: cell) {
cell.Heartcommentaction = {
cell.HeartCommentbutton.tintColor = .lightGray
tableView.reloadRows(at: [indexPath], .fade)
}
} else {
print("bad indexPath")
}
} else {
print("no child")
}
})
return cell
}

Pass value to next view when label in Table view cell is tapped

would love to pass the value postArray[indexpath.row].creatorId when the label inside a tableview cell is tapped so it can be passed onto the next view controller so i can load the profile of that particular creator/user. I used custom cells, so how do i get the creator id based on the location of the label(username) selected.
//custom cell
class PostCell : UITableViewCell
{
#IBOutlet weak var timeAgoLabel: UILabel!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var postImageView: UIImageView!
#IBOutlet weak var captionLabel: UILabel!
#IBOutlet weak var postStatsLabel: UILabel!
}
//do something when label is tapped
#objc func tapFunction(sender:UITapGestureRecognizer) {
//userClicked = creatorData
print(userClicked)
appDelegate.profileView()
print("tap working")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}else{
return postsArray.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//var returnCell: UITableViewCell!
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as! statusCell
profilePicture = UserDefaults.standard.object(forKey: "userPic") as? String
if profilePicture != nil {
//load profile picture from library
let urlString = "https://test.com/uploads/profile-picture/"+(profilePicture)!
let profileURL = URL(string: urlString)
cell.statusProfilePic?.downloadedFrom(url: profileURL!)
} else {
print("you have no profile picture set")
}
return cell
} else {
if postsArray[indexPath.row].photos != nil{
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
if postsArray[indexPath.row].comments != nil {
comments = postsArray[indexPath.row].comments?.count
} else {
comments = 0
}
if postsArray[indexPath.row].like_list != nil {
likes = postsArray[indexPath.row].like_list?.count
}else{
likes = 0
}
//assign post id to PostID
postID = postsArray[indexPath.row].post_id
//make username clickable!
let tap = UITapGestureRecognizer(target: self, action: #selector(NewsfeedTableViewController.tapFunction))
cell.usernameLabel.isUserInteractionEnabled = true
cell.usernameLabel.addGestureRecognizer(tap)
cell.usernameLabel.text = postsArray[indexPath.row].fullname
cell.timeAgoLabel.text = postsArray[indexPath.row].data_created
cell.captionLabel.text = postsArray[indexPath.row].content
cell.timeAgoLabel.text = postsArray[indexPath.row].modified
//15 Likes 30 Comments 500 Shares
cell.postStatsLabel.text = "\(likes!) Likes \(comments!) Comments"
//load profile picture from library
let urlString = "https://test.com/uploads/profile-picture/"+(postsArray[indexPath.row].profile_pic_filename)!
let profileURL = URL(string: urlString)
cell.profileImageView.downloadedFrom(url: profileURL!)
//iterate through posts images images array
//load post picture from server library
var postImageName : String?
if postsArray[indexPath.row].photos != nil{
let postImage = postsArray[indexPath.row].photos
for postsImage in postImage!{
postImageName = postsImage.filename!
}
let urlPostImageString = "https://test.com/uploads/post-picture/"+(postImageName)!
let postsImageUrl = URL(string: urlPostImageString)
cell.postImageView.downloadedFrom(url: postsImageUrl!)
} else {
print("Post has no picture")
}
//return cell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "NoImageCell", for: indexPath) as! NoImageTableViewCell
if postsArray[indexPath.row].comments != nil {
comments = postsArray[indexPath.row].comments?.count
} else {
comments = 0
}
if postsArray[indexPath.row].like_list != nil {
likes = postsArray[indexPath.row].like_list?.count
} else {
likes = 0
}
//make username clickable!
let tap = UITapGestureRecognizer(target: self, action: #selector(NewsfeedTableViewController.tapFunction))
cell.noImageUsername.isUserInteractionEnabled = true
cell.noImageUsername.addGestureRecognizer(tap)
cell.noImageUsername.text = postsArray[indexPath.row].fullname
cell.noImageTime.text = postsArray[indexPath.row].data_created
cell.noImagePost.text = postsArray[indexPath.row].content
cell.noImageTime.text = postsArray[indexPath.row].modified
//15 Likes 30 Comments 500 Shares
cell.noImageLikeAndComment.text = "\(likes!) Likes \(comments!) Comments"
//load profile picture from library
let urlString = "https://test.com/uploads/profile-picture/"+(postsArray[indexPath.row].profile_pic_filename)!
let profileURL = URL(string: urlString)
cell.noImageProfilePic.downloadedFrom(url: profileURL!)
return cell
}
}
}
Use this for example.
Implement didSelectRow() method and in it write something like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// this method works, when you taped cell. write here code of you need. Next code only example, which set user info to some VC and push it:
let controller = UserController as? UserController
if let controller = controller {
controller.user = users[indexPath.row]
self.navigationController?.pushViewController(controller, animated: true)
}
}
add this to your Cell's class:
func setTap() {
let tap = UITapGestureRecognizer(target: self, action: #selector(tapRecognized))
self.label.addGestureRecognizer(tap)
tap.numberOfTapsRequired = 1
}
#objc func tapRecognized(sender: UITapGestureRecognizer) {
// here your code of tap on label
print("label tapped")
}
Check on storyBoard is your label isUserInteractionEnabled? - set it to true. Inside tapRecodnized() method do what are you need. And you need to call method setTap() in your cell's method, which you call in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell.
Update
Simple example. this code know what are you tapped. if you tap cell, but not label, add code of push some controller, else code of push another controller.
Cell's Class:
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
var mainController: ViewController?
func setText(text: String) {
setTap()
label.text = text
}
func setTap() {
let tap = UITapGestureRecognizer(target: self, action: #selector(tapRecognized))
self.label.addGestureRecognizer(tap)
tap.numberOfTapsRequired = 1
}
#objc func tapRecognized(sender: UITapGestureRecognizer) {
if let mainController = mainController {
print("label tapped")
mainController.pushSomeVc(cell: self)
}
}
}
Code of main Class:
class ViewController: UIViewController {
#IBOutlet weak var myTableView: UITableView!
var array = ["1", "2", "3", "4", "5", "6"]
override func viewDidLoad() {
super.viewDidLoad()
}
func pushSomeVc(cell: MyTableViewCell) {
let row = myTableView.indexPath(for: cell)?.row
if let row = row {
// write here code of push controller, when label tapped. row property for get some user from array
print("push some vc with \(row)")
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "cell") as? MyTableViewCell
if let cell = cell {
cell.setText(text: array[indexPath.row])
cell.mainController = self
}
return cell ?? UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
// write here code of push controller with comments
print("cell tapped: \(indexPath.row)")
}
}
I tested this code and it's work perfect

How to preserve user input in UITableViewCell before dequeue

I'm creating an application in which I need the users to fill out a number of inputs in a UITableViewCell, kinda like a form. When the user taps on the done button, I need to collect those inputs so I can run some calculations and output them on another view controller
Here is the method I used to collect those inputs:
func doneButtonTapped() {
var dict = [String: Any]()
for rows in 0...TableViewCells.getTableViewCell(ceilingType: node.ceilingSelected, moduleType: node.moduleSelected).count {
let ip = IndexPath(row: rows, section: 0)
let cells = tableView.cellForRow(at: ip)
if let numericCell = cells as? NumericInputTableViewCell {
if let text = numericCell.userInputTextField.text {
dict[numericCell.numericTitleLabel.text!] = text
}
} else if let booleanCell = cells as? BooleanInputTableViewCell {
let booleanSelection = booleanCell.booleanToggleSwitch.isOn
dict[booleanCell.booleanTitleLabel.text!] = booleanSelection
}
}
let calculator = Calculator(userInputDictionary: dict, ceiling_type: node.ceilingSelected)
}
The problem I'm having is when the cell is out of view, the user's input is cleared from the memory. Here are two screenshots to illustrate my point:
As you can see, when all the cells appears, the done button managed to store all the inputs from the user, evidently from the console print. However, if the cells are out of view, the inputs from area/m2 are set to nil:
The solution that came to mind was I shouldn't use a dequeue-able cell as I do want the cell to be in memory when it is out-of-view, but many of the stackover community strong against this practice. How should I solve this problem? Thanks!
UPDATE
Code for cellForRow(at: IndexPath)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let node = node else {
return UITableViewCell()
}
let cellArray = TableViewCells.getTableViewCell(ceilingType: node.ceilingSelected, moduleType: node.moduleSelected)
switch cellArray[indexPath.row].cellType {
case .numericInput :
let cell = tableView.dequeueReusableCell(withIdentifier: "numericCell", for: indexPath) as! NumericInputTableViewCell
cell.numericTitleLabel.text = cellArray[indexPath.row].title
return cell
case .booleanInput :
let cell = tableView.dequeueReusableCell(withIdentifier: "booleanCell", for: indexPath) as! BooleanInputTableViewCell
cell.booleanTitleLabel.text = cellArray[indexPath.row].title
return cell
}
}
}
My two custom cells
NumericInputTableViewCell
class NumericInputTableViewCell: UITableViewCell {
#IBOutlet weak var numericTitleLabel: UILabel!
#IBOutlet weak var userInputTextField: UITextField!
}
BooleanInputTableViewCell
class BooleanInputTableViewCell: UITableViewCell {
#IBOutlet weak var booleanTitleLabel: UILabel!
#IBOutlet weak var booleanToggleSwitch: UISwitch!
}
Any takers?
I agree with the other contributors. The cells should not be used for data storage. You should consider another approach (like the one HMHero suggests).
But, as your question was also about how to access a UITableViewCell before it is removed, there is a method in UITableViewDelegate that you can use for that:
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// do something with the cell before it gets deallocated
}
This method tells the delegate that the specified cell was removed from the table. So it gives a last chance to do something with that cell before it disappears.
Because of table view reuses its cells, usually, it's not a good idea if your data depends on some components from the table view cell. Rather, it should be the other way around. Your table view data always drive it's table view cell's component even before any user input data is provided in your case.
Initial Data - your should already have somewhere in your code. I created my own from your provided code
let data = CellData()
data.title = "Troffer Light Fittin"
data.value = false
let data2 = CellData()
data2.title = "Length Drop"
data2.value = "0"
cellData.append(data)
cellData.append(data2)
Example
enum CellType {
case numericInput, booleanInput
}
class CellData {
var title: String?
var value: Any?
var cellType: CellType {
if let _ = value as? Bool {
return .booleanInput
} else {
return .numericInput
}
}
}
protocol DataCellDelegate: class {
func didChangeCellData(_ cell: UITableViewCell)
}
class DataTableViewCell: UITableViewCell {
var data: CellData?
weak var delegate: DataCellDelegate?
}
class NumericInputTableViewCell: DataTableViewCell {
let userInputTextField: UITextField = UITextField()
override var data: CellData? {
didSet {
textLabel?.text = data?.title
if let value = data?.value as? String {
userInputTextField.text = value
}
}
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
userInputTextField.addTarget(self, action: #selector(textDidChange(_:)), for: .editingChanged)
contentView.addSubview(userInputTextField)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func textDidChange(_ textField: UITextField) {
//update data and let the delegate know data is updated
data?.value = textField.text
delegate?.didChangeCellData(self)
}
//Disregard this part
override func layoutSubviews() {
super.layoutSubviews()
textLabel?.frame.size.height = bounds.size.height / 2
userInputTextField.frame = CGRect(x: (textLabel?.frame.origin.x ?? 10), y: bounds.size.height / 2, width: bounds.size.width - (textLabel?.frame.origin.x ?? 10), height: bounds.size.height / 2)
}
}
class BooleanInputTableViewCell: DataTableViewCell {
override var data: CellData? {
didSet {
textLabel?.text = data?.title
if let value = data?.value as? Bool {
booleanToggleSwitch.isOn = value
}
}
}
let booleanToggleSwitch = UISwitch(frame: .zero)
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
booleanToggleSwitch.addTarget(self, action: #selector(toggled), for: .valueChanged)
booleanToggleSwitch.isOn = true
accessoryView = booleanToggleSwitch
accessoryType = .none
selectionStyle = .none
}
func toggled() {
//update data and let the delegate know data is updated
data?.value = booleanToggleSwitch.isOn
delegate?.didChangeCellData(self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In View Controller, you should update your original data source so when you scroll the table view, the data source privide right infomation.
func didChangeCellData(_ cell: UITableViewCell) {
if let cell = cell as? DataTableViewCell {
for data in cellData {
if let title = data.title, let titlePassed = cell.data?.title, title == titlePassed {
data.value = cell.data?.value
}
}
}
for data in cellData {
print("\(data.title) \(data.value)")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = cellData[indexPath.row]
let cell: DataTableViewCell
if data.cellType == .booleanInput {
cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(BooleanInputTableViewCell.self), for: indexPath) as! BooleanInputTableViewCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(NumericInputTableViewCell.self), for: indexPath) as! NumericInputTableViewCell
}
cell.data = cellData[indexPath.row]
cell.delegate = self
return cell
}
In short, try to have a single data source for table view and use the delegate to pass the updated data in the cell back to the data source.
Please disregard anything that has to do with layout. I didn't use the storyboard to test your requirements.

Calling a function in another class Swift

I need to call this function. I need to receive the user identityString. How can i go about doing this?
class GeneralChatroom: UIViewController,
UITableViewDataSource,
UITableViewDelegate,
UITextFieldDelegate,
UITextViewDelegate {
//Get Data of current cell that has been tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let userIdentityString = generalRoomDataArr[indexPath.row].cellUserId
print("Uid of cell Data: " + userIdentityString!)
print("section: \(indexPath.section)")
print("row: \(indexPath.row)")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
//Transform Data From ^ to load at the bottom
tableView.transform = CGAffineTransform (scaleX: 1,y: -1);
cell?.contentView.transform = CGAffineTransform (scaleX: 1,y: -1);
cell?.accessoryView?.transform = CGAffineTransform (scaleX: 1,y: -1);
//Set username label to display username
let usernameLabel = cell?.viewWithTag(1) as! UILabel
usernameLabel.text = generalRoomDataArr[indexPath.row].username
//Set mesage TextView Label to display message in textView
let messageLabel = cell?.viewWithTag(5) as! UITextView
messageLabel.text = generalRoomDataArr[indexPath.row].message
//TO DO: dont know if this actually works prob can delete
messageLabel.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
//initialize UI Profile Image
let imageView = cell?.viewWithTag(3) as! UIImageView
//Make Porfile Image Cirlce
imageView.layer.cornerRadius = imageView.frame.size.width/2
imageView.clipsToBounds = true
//Set timeStampLabel to current time AGO
let timeStampLabel = cell?.viewWithTag(4) as! UILabel
timeStampLabel.text = generalRoomDataArr[indexPath.row].timeStamp
timeStampLabel.numberOfLines = 0
//Loading and change of Usesrs profile image on chat cell
let userProfileChatImage = generalRoomDataArr[indexPath.row].photoURL
//Load profile image(on cell) with URL & Alamofire Library
let downloadURL = NSURL(string: userProfileChatImage!)
imageView.af_setImage(withURL: downloadURL as! URL)
return cell!
}
}
But I need to call that function in a different class to get the userIdentityString. How can I do this? I need to call it in the Image Tapped function.
class GeneralChatroomTableViewCell: UITableViewCell {
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var textViewHeight: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
// You must to use interaction enabled
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(imageTapped(_:))))
}
func imageTapped(_ sender: UITapGestureRecognizer) {
//first you need to call the function that reads the cell. Recieve the UID
print("image tapped")
}
}
maybe this will be more clear
func imageTapped(_ sender: UITapGestureRecognizer) {
let userIDString = GeneralChatroom.tableView(userIdentityString: userIdentityString)
print(userIDString)
//first you need to call the function that reads the cell. Recieve the UID
print("image tapped")
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) -> String{
let userIdentityString = generalRoomDataArr[indexPath.row].cellUserId
print("Uid of cell Data: " + userIdentityString!)
print("section: \(indexPath.section)")
print("row: \(indexPath.row)")
//1.) If imageView touch is deteected
//2.) Segua to new view controller by passing in the string UID(userIdentityString) of the cell
//3.) Get database information based on the UID that is added(look at prevous methods)
// -might have to call this function and use separeate function
//4.) Output data from database Users to represent a user profile
//All you have to do is pass a UID (Check other Database methods to send UID)
return userIdentityString!
}
OK, as I stated in my comment this answer is not about calling another function from a swift class because you are trying to call a delegate function. I am not sure it can be guaranteed that function will have the expected value if called manually. What I would do is create a property on your TableViewCell to hold the userId.
class GeneralChatroomTableViewCell: UITableViewCell {
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var textViewHeight: NSLayoutConstraint!
// User Id
var userId: String?
override func awakeFromNib() {
super.awakeFromNib()
// You must to use interaction enabled
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(imageTapped(_:))))
}
func imageTapped(_ sender: UITapGestureRecognizer) {
//first you need to call the function that reads the cell. Recieve the UID
print("image tapped")
if let uid = self.userId {
// Do whatever you want with userId
}
}
}
So I added an optional userId property on the TableViewCell. In order to populate that we will do it in the func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { delegate function. I am not sure what yours looks like since you didn't provide that code so I am just going on what it generally looks like and what your GeneralChatroomTableViewCell is.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(GeneralChatroomTableViewCell.self), for: indexPath) as! GeneralChatroomTableViewCell
(cell as! GeneralChatroomTableViewCell).userId = generalRoomDataArr[indexPath.row].cellUserId
return cell
}
This function is called whenever a cell is being created for display in the table. So now on creation of the cell we set the userId so that its always available for us whenever we need it.
And as stated in the comment above this is only useful if that data is available at the time of creation of the cell.

Resources