Set cell text label to text passed through delegate function - ios

I have some text that is being passed to my view controller, and I am trying to set the cell label text to this.
class oneViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, TypingDelegate {
#IBOutlet var tableView: UITableView!
var someText:String = ""
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("TextA: \(someText)")
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell")
cell.textLabel.text = someText
return cell
}
...
func data(passedData:String) {
someText = passedData
print("TextB: \(someText)")
}
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showSecondVC" {
let sendingVC:OtherViewController = segue.destination as! OtherViewController
sendingVC.myDelegate = self
}
}
}
When I run this code I get:
TextB: "pizza"
TextA: ""
It seems like the passed value of "pizza" is overwritten to "" every time the view is loaded. How do you take the passed data from the delegate function and set the cell text label to that value?
Edit
Here is the code of the other (sending VC):
protocol TypingDelegate {
func data(passedData:String)
}
class TypingViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate {
var myDelegate:TypingDelegate? = nil
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
if myDelegate != nil {
let passedData = "pizza"
myDelegate?.typingData(passedName: passedName)
searchController.isActive = false
performSegue(withIdentifier: "showOtherVC", sender: self)
}
}
...
}
Thanks

The unexpected behavior may be caused by your delegate function being called AFTER the table view loads.
Simply do this to reload the tableView after the delegate function is called
func data(passedData:String) {
someText = passedData
print("TextB: \(someText)")
tableView.reloadData()
}
Note that this will set the text label for every cell to someText. Use a collection type (array, dictionary) to store ordered values that you can read in accordance with the indexPath's row property ( indexPath.row)

Related

How to press on a tableview cell to present a view controller with the text in navigation controller

Essentially I have a view controller called FirstViewController, this view controller contains a table view within it called listTableView.
I would like to tap on one of the cells in the table view listTableView and present whatever text was in the cell as the navigation controller title.
The navigation controller that appears when the cell is tapped is called showDetailsViewController.
How can this be done?
The following is what I have written in the FirstViewController
import UIKit
import AudioToolbox
class FirstViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FeedModelProtocol {
var feedItems: NSArray = NSArray()
var selectedStock : StockModel = StockModel()
let tableView = UITableView()
#IBOutlet weak var listTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
//set delegates and initialize FeedModel
self.listTableView.delegate = self
self.listTableView.dataSource = self
let feedModel = FeedModel()
feedModel.delegate = self
feedModel.downloadItems()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
#IBAction func reloadData(_ sender: Any) {
print("reload pressed")
listTableView.reloadData()
viewDidLoad()
_ = AudioServicesPlaySystemSound(1519)
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.listTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of feed items
print("item feed loaded")
return feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Retrieve cell
let cellIdentifier: String = "stockCell"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
myCell.textLabel?.textAlignment = .center
myCell.textLabel?.font = .boldSystemFont(ofSize: 18)
// Get the stock to be shown
let item: StockModel = feedItems[indexPath.row] as! StockModel
// Configure our cell title made up of name and price
let titleStr = [item.customer].compactMap { $0 }.joined(separator: "-")
print(titleStr)
// Get references to labels of cell
myCell.textLabel!.text = titleStr
return myCell
}
}
UPDATE:
What is the issue with this code:
NOTE:
The restoration id of the tableview is scheduleTable
var homeworkIdentifierFromTableViewCell = ""
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
homeworkIdentifierFromTableViewCell = feedItems[indexPath.row].myCell
self.performSegue(withIdentifier: "scheduleTable", sender: self)
listTableView.deselectRow(at: indexPath, animated: true)
}
UPDATE 2
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item: StockModel = feedItems[indexPath.row] as! StockModel
let titleStr = [item.customer].compactMap { $0 }.joined(separator: "-")
print(titleStr)
}
You can use the didSelectRowAt to notice what cell was clicked and store what the text in the cell was (homeworkArray is the list of cells from a struct. Homeworkidentifier is a value in the struct).
var homeworkIdentifierFromTableViewCell = ""
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
homeworkIdentifierFromTableViewCell = homeworkArray[indexPath.row].homeworkIdentifier
self.performSegue(withIdentifier: "homeworktoExpandHomework", sender: self)
homeworkTableView.deselectRow(at: indexPath, animated: true)
}
Then, you could use a prepare for a segue function to pass the text of the table view cell to the next view controller. You do this by creating a variable in the other view controller (the one that you are going to pass data to) and later accessing it from the other view controller and changing its value.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "reportBug" {
let destinationViewController = segue.destination as! WebViewController
destinationViewController.reason = "reportBug"
}
else if segue.identifier == "provideFeedback" {
let destinationViewController = segue.destination as! WebViewController
destinationViewController.reason = "provideFeedback"
}
}
Here is more about passing data between viewcontrollers : Passing data between View Controllers in Swift (From TableView to DetailViewController)
Hope this helps
EDIT:
Here is the struct I am using :
struct homeworkTableViewCellData {
let homeworkName : String!
let className : String!
let dateName : String!
let colorImage : UIImage!
let homeworkIdentifier : String!
}
I have initialized my homeworkArray with this struct. When I am calling a value from the cell, I am picking one from in the struct.
To set the table view with a struct is more organized. This is a good video that teaches you how to set it up (if you are want to do that) : https://www.youtube.com/watch?v=zAWO9rldyUE&list=LL--UalPCi7F16WzDFhMEg7w&index=20&t=921s

Table view cell elements not able to click and get data

I have one table view and inside that i placed one main view. And inside that main view i placed one button.And when ever use click on my cell button. I need to get the cell title label.This is what i need. But i tried following below code. Not sure what i am missing out. It not at all calling my cell.add target line.
Code in cell for row at index:
cell.cellBtn.tag = indexPath.row
cell.cellBtn.addTarget(self, action:#selector(self.buttonPressed(_:)), for:.touchUpInside)
#objc func buttonPressed(_ sender: AnyObject) {
print("cell tap")
let button = sender as? UIButton
let cell = button?.superview?.superview as? UITableViewCell
let indexPath = tableView.indexPath(for: cell!)
let currentCell = tableView.cellForRow(at: indexPath!)! as! KMTrainingTableViewCell
print(indexPath?.row)
print(currentCell.cellTitleLabel.text)
}
I even added a breakpoint, still it not at calling my cell.addTarget line
Tried with closure too. In cell for row at index:
cell.tapCallback = {
print(indexPath.row)
}
In my table view cell:
var tapCallback: (() -> Void)?
#IBAction func CellBtndidTap(_ sender: Any) {
print("Right button is tapped")
tapCallback?()
}
Here that print statement is getting print in console.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var list = [String]()
#IBOutlet weak var tableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.saveButton.tag = indexPath.row
//cell.saveButton.accessibilityIdentifier = "some unique identifier"
cell.tapCallback = { tag in
print(tag)
}
return cell
}
}
class MyTableViewCell: UITableViewCell {
// MARK: - IBOutlets
#IBOutlet weak var saveButton: UIButton!
// MARK: - IBActions
#IBAction func saveTapped(_ sender: UIButton) {
tapCallback?(sender.tag)
}
// MARK: - Actions
var tapCallback: ((Int) -> Void)?
}
Actually this is not a good programming practice to add the button (which contains in table view cell) target action in view controller. We should follow the protocol oriented approach for it. Please try to under stand the concept.
/*This is my cell Delegate*/
protocol InfoCellDelegate {
func showItem(item:String)
}
/*This is my cell class*/
class InfoCell: UITableViewCell {
//make weak reference to avoid the Retain Cycle
fileprivate weak var delegate: InfoCellDelegate?
//Outlet for views
#IBOutlet var showButton: UIButton?
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
//This is the public binding function which will bind the data & delegate to cell
func bind(with: DataModel?, delegate: InfoCellDelegate?, indexPath: IndexPath) {
//Now the bind the cell with data here
//.....
//Assign the delegate
self.delegate = delegate
}
//Button action
#IBAction func rowSelected(sender: UIButton) {
self.delegate?.showItem(item: "This is coming from cell")
}
}
/*Now in your ViewController you need to just confirm the InfoCellDelegate & call the bind function*/
class ListViewController: UIViewController {
//Views initialisation & other initial process
}
//Table view Delegate & Data source
extension ListViewController: UITableViewDataSource, UITableViewDelegate {
/**
Configure the table views
*/
func configureTable() {
//for item table
self.listTable.register(UINib.init(nibName: "\(InfoCell.classForCoder())", bundle: nil), forCellReuseIdentifier: "\(InfoCell.classForCoder())")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InfoCell") as! InfoCell
cell.bind(with: DataModel, delegate: self, indexPath: indexPath)
return cell
}
}
extension ListViewController: InfoCellDelegate {
func showItem(item) {
print(item)
}
}

Segue from TableView into another Tableview using gesture

I have FirstTableView (TableView) which is populated by cells that have an image and label. If users tap the label, I want to segue into another tableview (SecondTableView), which will use the label from the previous tableview as a path(foldername) to search for images within that folder and display them as cells.
I have bits and pieces of the code written together, but I'm not quite sure where to pass the perform segue and prepare for segue functions.
Here is the extension of my FirstTableViewController, which populate the cells of the FirstTableView:
FirstTableView
extension FirstTableViewController: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataCells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let folderCell = dataCells[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstTableCell") as! FirstTableViewCell
cell.setCell(cell:folderCell)
return cell
}
}
Here is the code for the FirstTAbleViewCell. Notice that I've created the UITapGestureRecognizer constant and a protocol. If the FolderLabel is clicked, I want to segue into the next tableview.
func setCell is just the function to populate the FirstTableViews.
FirstTableViewCells
import UIKit
protocol LabelCellDelegate {
func func1(sender:Any)
}
class FirstTableViewCell: UITableViewCell {
#IBOutlet weak var ImageView: UIImageView!
#IBOutlet weak var FolderLabel: UILabel!
var delegate: LabelCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
FolderLabel.isUserInteractionEnabled = true
let recognizer = UITapGestureRecognizer(target: self, action:Selector(("handleTap:")))
recognizer.numberOfTapsRequired = 1
self.FolderLabel.addGestureRecognizer(recognizer)
}
func handleTap(recognizer: UITapGestureRecognizer){
delegate!.func1(sender: self)
}
func setCell (cell : FolderCell){
self.ImageView.image = cell.image
self.FolderLabel.text = cell.label
}
}
Next is the SecondTableViewController.
Somehow, after the tap of the cell from the FirstTableView I want to get the label name that was tapped, and use that name as a directory to search.
Grab all the images within the directory and display them as images in cells in SecondTableView. I'm not quite sure where I should be calling the gesture function and which TableViewController should be the delegate of the cell protocol.
SecondTableView
import UIKit
class SecondTableViewController: UIViewController {
var Imagefiles: [String] //Imagefiles String. This are all images from tapped folder label.
var CellObjects: [folderCell] // Cellobjects to fill the cells. contains images and image names.
// need to get folder name from FirstTableViewCell how?
override func viewDidLoad() {
super.viewDidLoad()
imageFiles = getImageObjects(folder: Foldercell) //how to get access to folderCell???????
cellObjects = createArray(imageFiles: imageFiles)
}
func getImageObjects(folder: FolderCell) -> imageFiles: String {
//FUNCTION To search tapped label and grab all image file paths.
func createArray(imageFiles: string)-> tempArray: [folderCell]{
//We use this function to take the image files from above function and
//create cell objects to populate our cells
//in SecondTableView
}
}
}
}
extension ViewController: LabelCellDelegate{
func1(folderLabel : String) {
return folderLabel
}
}
extension LablesTableView:UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return CellObjects.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellFolderObject = folderObjects[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondCell") as! LabelCell
let folderCell = CellObjects[indexPath.row]
cell.setCell(cell: folderCell)
return cell
As you can see, I haven't called perform segue and prepare for segue. I'm not sure where I should be calling them.
I'm also unsure about where the delegate to the gesture protocol should be.
Thank you.
Inside cellForRowAt set
cell.delegate = self
//
then inside this delegate function of the VC ( conform to the protocol LabelCellDelegate )
extension FirstTableViewController:LabelCellDelegate {
func func1(sender: FirstTableViewCell) {
self.performSegue(withIdentifier: "goToSecond", sender:sender.FolderLabel.text!)
}
}
//
the VC method is triggered from here
func handleTap(recognizer: UITapGestureRecognizer){
delegate!.func1(sender: self)
}
//
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondController = segue.destination as? SecondTableViewController {
secondController.sendedStr = sender as! String
}
}

What is the missing command to carry the cell title from UITableView to new ViewController via this segue?

I have ViewController that contains a UITableView. Data is loaded into that table via the following code:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UsernameSentDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var receiveUsername: UILabel!
#IBOutlet weak var userEmailText: UILabel!
var userEmail: String?
var communities = [String]() { didSet { communitiesTableView.reloadData()
}
}
var flag = false
#IBOutlet weak var communitiesTableView: UITableView!
#IBAction func unwindToHome(_ segue: UIStoryboardSegue) {
}
//recieves email address from delegate from LoginViewController
func userLoggedIn(data: String) {
userEmailText.text = data
}
override func viewDidLoad() {
super.viewDidLoad()
self.communitiesTableView.delegate = self
self.communitiesTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.communities.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let title = self.communities[indexPath.row]
let cell = UITableViewCell()
cell.textLabel?.text = title
return cell
}
I then set up 1 prototype cell within the UITableView so I could create a segue to my second view controller, ShowCommunitiesViewController and named this segue, "showCommunitySegue"
In ShowCommunitiesViewController I have a label set up and ready to use as the title of the cell name carried across, named communityName.
In ViewController I have set up the following function to deal with the segue, including the destination variable for the cell title that has been selected.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "showCommunitySegue", sender: self)
showCommunityController.communityName = //what do I put here?
}
What do I need to put on that last line so showCommunityController.communityName displays the cell title?
Just declare selectedCellTitle as String in your viewController where your cells are.
var selectedCellTitle: String?
This will be the global variable keeping track of the selected cell's title.
Add the following in didSelectRowAt:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Set your global variable to the title
self.selectedCellTitle = self.communities[indexPath.row]
// Trigger your segue
performSegue(withIdentifier: "showCommunitySegue", sender: self)
}
Override prepareforsegue method the following way:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showCommunitySegue" {
// Check if the segue's destination viewcontroller is your viewcontroller
if let showCommunityController = segue.destination as? ShowCommunityViewController {
// Assign the selected title to communityName
showCommunityController.communityName = self.selectedCellTitle
}
}
}

How do I send specific data based on which cell is clicked?

I have a tableview with a bunch of concerts, and when x cell is clicked, I want the artist of that concert to populate the new tableView. Below is the code for the first view controller (the view controller with all the concerts).
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView1: UITableView!
var arrayOfConcerts: [concert] = [concert]()
override func viewDidLoad()
{
super.viewDidLoad()
self.setUpConcerts()
self.tableView1.rowHeight = 145.0
}
func setUpConcerts()
{
var ACL = concert(imageName: "ACL2015.png")
let Landmark = concert(imageName: "Landmark.png")
let BostonCalling = concert(imageName: "BostonCalling.png")
let Lolla = concert(imageName: "Lolla.png")
arrayOfConcerts.append(ACL)
arrayOfConcerts.append(Landmark)
arrayOfConcerts.append(BostonCalling)
arrayOfConcerts.append(Lolla)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfConcerts.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = self.tableView1.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
let concerts = arrayOfConcerts[indexPath.row]
cell.setCell(concerts.imageName)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("concertartist", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
}
}
Below is the code for the Artist View Controller (the second
viewcontroller). This tableView should be populated with specific
artists.
How would I go about doing that?
class ArtistConcerts: UIViewController, UITableViewDataSource, UITableViewDelegate {
var arrayOfArtists: [artist] = [artist]()
#IBOutlet weak var tableViewArtists: UITableView!
override func viewDidLoad()
{
super.viewDidLoad()
self.setUpArtists()
}
func setUpArtists()
{
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfArtists.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableViewArtists.dequeueReusableCellWithIdentifier("", forIndexPath: indexPath) as! CustomCell
let artists = arrayOfArtists[indexPath.row]
cell.setCell(artists.imageNameArtist)
return cell
}
}
You need to do this in the prepareForSegue method.
let vc = segue!.destinationViewController as! ArtistConcerts
if let rowSelected = tableView.indexPathForSelectedRow()?.row {
vc.arrayOfArtists = artistsPerforming[0]//this is an array
}
then, set whatever data you need to actually populate the tableView in that new view controller. I am not 100% sure on what you are trying to do though. Does my answer make sense?
you can send data once the cell is pressed to another viewcontroller by using didSelectRowAtIndexPath or prepareForSegue or didSelectRowAtIndexPath + prepareForSegue
let's say you are using prepareForSegue, things you will need
the segue identifier name
cast the destinationController to the controller you want to send the data
the indexPath.row where the cell was selected
then set the variable or variables or data structure that should receive data
Create a segue when you pressed CTRL + Drag from your cell into another viewcontroller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if segue.identifier == "Name_Of_Segue"
{
let destination = segue.destinationViewController as! NAME_Of_ViewController
let indexPath = mytableview.indexPathForSelectedRow!
let data = arrayOfArtists[indexPath.row]
destination.artist = data
}
mytableview is an IBOutlet from your tableview
artist is a variable that is declared in your destination controller
destination.artist = data this line of code is passing data from the specific cell then send it to your destination cell

Resources