ViewControllerA will be pushing to ViewControllerB. ViewcontrollerB is a UITableView that has a custom UITableViewCell that is registered upon load.
Here is my custom UITableViewCell:
override func awakeFromNib() {
super.awakeFromNib()
// Here is me attempting to pass my data from my view controller
someButton.text = stringFromViewController
}
Here's my UITableView:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let customCell = CustomCell()
customCell.stringFromViewController = "Some Text"
self.performSegueWithIdentifier("ViewControllerB", sender: nil)
}
Whenever I attempt this the string comes back as empty. I'm not sure if this has to do with the fact that I am trying to pass this data to the UITableViewCell instead of the UITableView that contains the custom cell. I'd like to pass the data to my custom cell class.
You going about this the wrong way.
your tableView is reloading automatically upon loading controller B.
you should pass the data to the cell in tableView:CellForRow: method.
you can also call tableView.reloadData() once you assign the value from controller A.
here's an example:
class ControllerB {
var tableView: UITableView! //IBOutlet?
var stringFromA: String? {
didSet {
self.tableView.reloadData()
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell")
cell.stringFromA = self.stringFromA
return cell
}
Because awakeFromNib() initilizes even before you initilize the cell.
instead of assigning it in this method use this in didSelectRowAtIndexPath
let customCell = CustomCell()
customCell.someButton.setText("Some Text", forState: .Normal)
self.performSegueWithIdentifier("ViewControllerB", sender: nil)
My understanding of your question is that clicking on a row from View Controller A will push View Controller B and you want to pass some data to the custom cell in View Controller B. you have to use prepareForSegue to pass the data.
in view controller b, set a variable, and in your case, a bool.
class ViewControllerB {
var boolValue: Bool?
}
then in didSelectRowAtIndexPath in ViewControllerA you perform the segue
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("ViewControllerB", sender: nil)
}
Then you have to perform prepareForSegue according to the row being selected
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "ViewControllerB" {
//if you need to know which row is select, use indexPath.row
if let indexPath = tableView.indexPathForSelectedRow {
let controller = segue.destinationViewController as! ViewControllerB
//send the details that you want, i.e
if indexPath.row < 5 {
controller.boolValue = true
} else {
controller.boolValue = false
}
}
}
once the segue is called, you pass the data through prepareForSegue, then you can pass the information to the cell using cellForRowAtIndexPath method.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomTableViewCell
//pass the boolValue from viewcontrollerB to anotherBoolValue in custom cell
cell.anotherBoolValue = boolValue
// Configure the cell...
return cell
}
I agree with #Lirik
have a property observer on you controllerB's property and reload the table view, then in your cellForRowAtIndexPath(::)
cast the dequeued cell to your custom cell type so that you can access all the function of your cell
let cell:CustomCell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! CustomCell
cell.someBotton.text = stringFromViewControllerA
I agree with #Lirik
have a property observer on you controllerB and reload the table view, then in your cellForRowAtIndexPath(::)
cast the dequeued cell to your custom cell type so that you can access all the function of your cell
let cell:CustomCell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! CustomCell
Related
I have an UITableView, in each cell it's have some label and a button. I want to get all label value when I click the button. How to do this? Thank you.
You can do it by closure or delegation
1: Closure
In your tableViewCell class create a variable like this
customObject is the object you passed the tableviewCell to load the data
var cellData: customObject? {
didSet {
// do your loding labels in here
}
}
var clickHandler: ((customObject) -> Void)!
and inside of you action button add this
#IBAction func replyAction(_ sender: Any) {
if let customObject = customObject {
clickHandler(customObject)
}
}
now go to where are you deque the table
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCustomCell
// add this
cell.clickHandler = { customObject in
print("myCell.customObject = \(customObject)")
}
}
this will do the magic
2. Delegation
Create a delegate methode like this
protocol CustomCellDelegate {
func getCustomObject(in cell: CustomCell, withCustomObject object: CustomObject)
}
now in your cell class add delegate variable
var delegate: CustomCellDelegate?
and inside of you action button add this
#IBAction func replyAction(_ sender: Any) {
if let customObject = customObject {
delegate.getCustomObject(in: self, withCustomObject: customObject)
}
}
and now for the last part go to class you implemented the table view and this to where it shows
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCustomCell
// add this
cell.delegate = self
}
and inside of class you should add you delegate method
extension YourClass: CustomCellDelegate {
getCustomObject(in cell: CustomCell, withCustomObject object: CustomObject) {
print("current cell data = \(CustomObject)"
}
}
this will do the job too
Hop this will Helps
Create IBAction method for the button inside the cell custom class and inside it print
print("label text : \(self.lbl.text)")
Or use delegate to send that value to the VC the contains the tableView
First of all. You should have a model object which you are using it to load the values of label. Use
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
to get the index then try getting the value from the model using the index
for example you have an array myArray then you could access the value using myArray[indexPath.row] to get the value. Then save, pass and use it where ever you want. Then implement a delegate method in your custom table cell class passing the indexPath. Then refresh the cell using tableView.reloadRows(at: [IndexPath(item:0,section:0)], with: .fade)
Usually, We use the dequeueReuseableCellwithIdentifier method in ViewController class but I want to use this method in the UITableViewCell.I have tried but I got the exception like this.
fatal error: unexpectedly found nil while unwrapping an optional value
ViewController Class:
#IBOutlet var tableView: UITableView!
var tableData:[songData] = [songData]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.backgroundColor = UIColor.orangeColor()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = TableViewCell()
cell.datas()
return cell
}
}
TableViewCell Class:
#IBOutlet var text1: UILabel!
#IBOutlet var text2: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func datas(){
let vc = ViewController()
let tableData = vc.tableData
print(tableData)
let tableview = vc.tableView
let indexpath:NSIndexPath = NSIndexPath()
let cell = tableview.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexpath) as! TableViewCell //The fatal error is showing exactly at this line.
let artistAndAlbum = tableData[indexpath.row]
cell.text1.text = artistAndAlbum.country
cell.text2.text = artistAndAlbum.currency
tableview.reloadData()
}
I need to customize my table data in the TableViewCell class.If it is possible help me or else why it is not possible?
You're going about this the wrong way. It honestly doesn't make any sense for your table cell subclass to be creating itself. It does make sense, however, for your cell subclass to be passed data and for it to populate itself from that.
You should have your view controller dequeue the cell as normal and then change your table cell function to take some data as a parameter and update itself.
In your view controller:
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerNib(UINib(nibName: "INSERT_NIB_NAME", bundle: nil), forCellReuseIdentifier: "Cell")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.updateWithData(tableData[indexPath.row])
return cell
}
If your cell is a prototype cell in the storyboard then you have to set the reuse identifier there instead of registering in viewDidLoad.
In your table cell:
func updateWithData(artistAndAlbum: songData) {
text1.text = artistAndAlbum.country
text2.text = artistAndAlbum.currency
}
In your view controller's viewDidLoad(), register the class with a reuse identifier.
tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "ID")
Then your cellForRowAtIndexPath method can dequeue your custom cell.
tableView.dequeueReuseableCellWithIdentifier("ID", indexPath: indexPath)
This isn't just limited to view controllers. If you have a custom table view cell, then register the class for a reuse identifier wherever you setup the table view and then dequeue your custom cell with that identifier in its cellForRowAtIndexPath.
As a general rule of thumb, your view should not keep a reference to its view controller. The view shouldn't care about any view controllers or need to know what the view controller is doing. Either the entire table view and all of its workings should go in your view, hidden from the view controller, or you should keep all of your table view code in the view controller. This will make your life much easier.
Firstly you must set name for cell identifier
after it in cellForRowAtIndexPath method used this code:-
for custom cell
CustomCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CELL" forIndexPath:indexPath];
//-------------------------------------------------------------
for normal cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CELL" forIndexPath:indexPath];
Check your vc.tableView. It's probably nil
I want to populate the prototype cells in a table view with information that the user has typed into a text field in a previous view controller. I want to set the title and subtitle of each cell using this data instead of a pre-determined array. How can I pass data from the text field inside a view controller to the title/subtitle section of a table cell view?
Any help is appreciated.
First of all implement this at the point where you want to segue to your TableViewController:
let textFieldString = yourTextField.text ?? ""
performSegueWithIdentifier("exampleID", sender: textFieldString)
Now create the right segue in your StoryBoard!
1) From the whole ViewController to your destination ViewController
2) And don't forget your unique segue-ID
The delegate method prepareForSegue(...) will be called before you perform the segue. In this method you prepare your destination ViewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let targetvc = segue.destinationViewController as? YourTableViewController
if let targetvc = targetvc
{
let yourTextFieldString = sender as? String
if let yourTextFieldString = yourTextFieldString
{
targetvc.yourTextFieldString = yourTextFieldString
}
}
}
When the segue to your destination ViewController is performed, your variable (here in this case "yourTextFieldString") has the previous set data.
class yourTableViewController : UITableViewController
{
var yourTextFieldString = "" // This variable has the previous set data
override func viewDidLoad()
{
super.viewDidLoad()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("yourCellID", forIndexPath: indexPath)
cell.textLabel.text = yourTextFieldString
return cell
}
}
Now adjust your prototype cell (don't forget the right identifier) and you're done.
I am a beginner in IOS programming, and in a whole programming.
(I have XCODE 6.4)
I have read so many tutorials, but i haven't found the information I need.
I have a code which assign a value to a label :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let identifier = "formuleTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) as! formule
let formuleCommand = formulesList[indexPath.row]
// Configure the cell...
var shortCut = formuleCommand.formuleText
cell.formuleLabel.text = shortCut
return cell
}
And then, I have a code, which have to get the label's name (I think so)
var valueToPass:String!
func tablView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
let identifier = "formuleTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath!) as! formule
valueToPass = cell.formuleLabel.text
performSegueWithIdentifier("detail", sender: self)
}
And finally, code, which passes the data from label to another ViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "detail") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as! specialitiesViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}
It have to work so:
Table view gets the data for cells (here is no code for this)
Then, method called TablView have to get cell's label.
And finally, i click on the cell and I move to another ViewController, where my Cell,s Label data prints in another Label.
But it don't work so, when I click on cell, I move to ViewController and the text in Label equals nil (i see no text). Why does it work so? Help me to fix this issue!
Thank you, for all your suggestions!
Your problem is that you're using the functiondequeueReusableCellWithIdentifier for get the cell and and this method only returns a cell if it has been marked as ready for reuse.
You need to use cellForRowAtIndexPath that is different from the delegate method, be carefull to get the cell, change your didSelectRowAtIndexPath like the following:
func tablView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// get cell label
let cell = tableView.cellForRowAtIndexPath(indexPath) as! formule
self.valueToPass = cell.formuleLabel.text
self.performSegueWithIdentifier("detail", sender: self)
}
I hope this help you.
I have a UITableView that populates Cells with data based on a JSON call. like so:
var items = ["Loading..."]
var indexValue = 0
// Here is SwiftyJSON code //
for (index, item) in enumerate(json) {
var indvItem = json[index]["Brand"]["Name"].stringValue
self.items.insert(indvItem, atIndex: indexValue)
indexValue++
}
self.tableView.reloadData()
How do I get the label of the cell when it is selected and then also pass that to another ViewController?
I have managed to get:
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
println(currentCell.textLabel.text)
}
I just cant figure out how to pass that as a variable to the next UIViewController.
Thanks
Passing data between two view controllers depends on how view controllers are linked to each other. If they are linked with segue you will need to use performSegueWithIdentifier method and override prepareForSegue method
var valueToPass:String!
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel.text
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "yourSegueIdentifer") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as AnotherViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}
If your view controller are not linked with segue then you can pass values directly from your tableView function
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
let storyboard = UIStoryboard(name: "YourStoryBoardFileName", bundle: nil)
var viewController = storyboard.instantiateViewControllerWithIdentifier("viewControllerIdentifer") as AnotherViewController
viewController.passedValue = currentCell.textLabel.text
self.presentViewController(viewContoller, animated: true , completion: nil)
}
You asked:
How do I get the label of the cell when it is selected and then also pass that to another ViewController?
I might suggest rephrasing the question as follows: "How do I retrieve the data associated with the selected cell and pass it along to another view controller?"
That might sound like the same thing, but there's an important conceptual distinction here. You really don't want to retrieve the value from the cell label. Our apps employ a MVC paradigm, so when you want to pass data information from one scene to another, you want to go back to the model (the items array), not the view (the text property of the UILabel).
This is a trivial example, so this distinction is a bit academic, but as apps get more complicated, this pattern of going back to the model becomes increasingly important. The string representation from the cell is generally is a poor substitute for the actual model objects. And, as you'll see below, it's just as easy (if not easier) to retrieve the data from the model, so you should just do that.
As an aside, you don't really need a didSelectRowAtIndexPath method at all in this case. All you need is a segue from the table view cell to the destination scene, give that segue a unique identifier (Details in my example), and then implement prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailsViewController {
let selectedRow = tableView.indexPathForSelectedRow!.row
destination.selectedValue = items[selectedRow]
}
}
Alternatively, if your segue is between the cell and destination scene, you can also use the sender of the prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailsViewController {
let cell = sender as! UITableViewCell
let selectedRow = tableView.indexPath(for: cell)!.row
destination.selectedValue = items[selectedRow]
}
}
But the idea is the same. Identify what row was selected, and retrieve the information from the model, the items array.
The above is Swift 3. For Swift 2.3, please see the previous version of this answer.
Okay..Its been 2 days I was searching for the answer that how could I be able to save the selected UITableViewCell label text data and display that data to an another label on an another View Controller which will come out after tapping on a cell. At last I have completed with the task and its successful. Here is the complete code with steps using Swift.I am using Xcode 6.4.
Step 1.
I have Two class assigned to the storyboard view controllers named "iOSTableViewControllerClass.swift" which is a Table View Controller and "iOSTutorialsViewControllerClass.swift" which is a normal View Controller.
Step 2.
Now make segue from iOSTableViewControllerClass to iOSTutorialsViewControllerClass by Control-dragging on the storyboard area and choose "show" from drop down menu. Click on this highlighted button according to the below image and perform the segue.
Step 3.
Now select the segue by clicking on the storyboard and give it an identifier on the Attributes Inspector. In this case I named it as "iOSTutorials"
Step 4.
Now on this step put a label on your cell as well as on the other view controller and make outlets of them on their corresponding classes.
In my case those are "#IBOutlet weak var iOSCellLbl: UILabel!" and " #IBOutlet weak var iOSTutsClassLbl: UILabel!".
Step 5.
Make a string type variable on the first Table View Controller Class. I did this as "var sendSelectedData = NSString()" also Make a string type variable on the second class. I did this as "var SecondArray:String!".
Step 6.
Now we are ready to go.
Here is the complete Code for first Class --
// iOSTableViewControllerClass.swift
import UIKit
class iOSTableViewControllerClass: UITableViewController, UITableViewDataSource,UITableViewDelegate {
// Creating A variable to save the text from the selected label and send it to the next view controller
var sendSelectedData = NSString()
//This is the outlet of the label but in my case I am using a fully customized cell so it is actually declared on a different class
#IBOutlet weak var iOSCellLbl: UILabel!
//Array for data to display on the Table View
var iOSTableData = ["Label", "Button", "Text Field", "Slider", "Switch"];
override func viewDidLoad() {
super.viewDidLoad()
//Setting the delegate and datasource of the table view
tableView.delegate = self
tableView.dataSource = self
//Registering the class here
tableView.registerClass(CustomTableViewCellClassiOS.self, forCellReuseIdentifier: "CellIDiOS")
//If your using a custom designed Cell then use this commented line to register the nib.
//tableView.registerNib(UINib(nibName: "CellForiOS", bundle: nil), forCellReuseIdentifier: "CellIDiOS")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return iOSTableData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellIDentifier = "CellIDiOS"
//In this case I have custom designed cells so here "CustomTableViewCellClassiOS" is the class name of the cell
var cell:CustomTableViewCellClassiOS! = tableView.dequeueReusableCellWithIdentifier(CellIDentifier, forIndexPath: indexPath) as? CustomTableViewCellClassiOS
if cell == nil{
tableView.registerNib(UINib(nibName: "CellForiOS", bundle: nil), forCellReuseIdentifier: CellIDentifier)
cell = tableView.dequeueReusableCellWithIdentifier(CellIDentifier) as? CustomTableViewCellClassiOS
}
//Here we are displaying the data to the cell label
cell.iOSCellLbl?.text = iOSTableData[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label text here and storing it to the variable
let indexPathVal: NSIndexPath = tableView.indexPathForSelectedRow()!
println("\(indexPathVal)")
let currentCell = tableView.cellForRowAtIndexPath(indexPathVal) as! CustomTableViewCellClassiOS!;
println("\(currentCell)")
println("\(currentCell.iOSCellLbl?.text!)")
//Storing the data to a string from the selected cell
sendSelectedData = currentCell.iOSCellLbl.text!
println(sendSelectedData)
//Now here I am performing the segue action after cell selection to the other view controller by using the segue Identifier Name
self.performSegueWithIdentifier("iOSTutorials", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Here i am checking the Segue and Saving the data to an array on the next view Controller also sending it to the next view COntroller
if segue.identifier == "iOSTutorials"{
//Creating an object of the second View controller
let controller = segue.destinationViewController as! iOSTutorialsViewControllerClass
//Sending the data here
controller.SecondArray = sendSelectedData as! String
}
Here is the complete code for the second Class..--
// iOSTutorialsViewControllerClass.swift
import UIKit
class iOSTutorialsViewControllerClass: UIViewController {
//Creating the Outlet for the Second Label on the Second View Controller Class
#IBOutlet weak var iOSTutsClassLbl: UILabel!
//Creating an array which will get the value from the first Table View Controller Class
var SecondArray:String!
override func viewDidLoad() {
super.viewDidLoad()
//Simply giving the value of the array to the newly created label's text on the second view controller
iOSTutsClassLbl.text = SecondArray
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I do it like this.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedName = nameArray[indexPath.row]
let newView: nextViewName = self.storyboard?.instantiateViewController(withIdentifier: "nextViewName") as! nextViewName
newView.label.text = selectedValue
self.present(newView, animated: true, completion: nil)
}