How to use navigationController.pushViewController inside nested tableview? - swift

I have a screen with this view hierarchy.
I have tableview inside collectionview, and in that tableview, I have reusable cell.
I want to implement navigationController.pushViewController() when I tap tableview cell which is located in collectinview cell(and of course this collection view cell is in collectionview).
So I tried to create delegate protocol inside collection view cell which holding tableview.
protocol PushViewControllerDelegate {
func pushViewController()
}
class CollectionViewCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource{
var delegate: PushViewControllerDelegate?
var tableView = UITableView()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.pushViewController()
}
}
And In the ViewController which hold all of these view hierarchies, wrote like :
class MainViewController: UIViewController, PushViewControllerDelegate {
let customCell = CollectionViewCell()
override func viewDidLoad() {
super.viewDidLoad()
customCell.delegate = self
}
func pushViewController() {
let vc = SecondVC()
navigationController?.pushViewController(vc, animated: true)
}
}
But this delegate method is not calling when I tap tableview cell.
How can I navigate using pushViewcontroller in my situation?

Related

Swift : How to instantiate a new view controller with separate delegate

so i have a question regarding instantiating a new vc when i click on a tableviewcell. Since i have separated my delegate and datasource into separate classes i no longer inherit from ViewController. What are my alternatives to creating a new VC from my delegate class? The other potential problem is that my show array is created in my other separate myDataSource class. How would i pass that to MyDelegate class?
class ViewController: UITableViewController {
let aDataSource = MyDataSource()
let aDelegate = MyDelegate()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = aDataSource
tableView.delegate = aDelegate
}
}
class MyDelegate: NSObject, UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// i want to do the following but it doesn't work since i'm not inheriting from viewcontroller i guess.
guard let vc = storyboard?.instantiateViewController(withIdentifier: "detailedShowViewController") as? DetailedShowViewController else {
fatalError("Unable to instantiate view controller.")
}
let item = shows[indexPath.row]
vc.show = item
navigationController?.pushViewController(vc, animated: true)
}
}
You can create a delegate and let your view controller inherit this delegate to handle the callback:
protocol MyViewControllerDelegate {
func didSelectItemAt(_ indexPath: IndexPath)
}
Create a new property such as weak var myVCDelegate: MyViewControllerDelegate? in your MyDelegate class.
Let your view controller inherit it and assign itself to the delegate from MyDelegate (or inject it into the class)
// In ViewController
aDelegate.myVCDelegate = self
// In MyDelegate class
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Do some stuff
// Pass the position of the item.
myVCDelegate?.didSelectItemAt(indexPath)
}
So, when you select a cell, just call the function to pass the indexPath to the view controller then you will be able to get the item by the indexPath from your data source.

Send data from CustomTableView Class to its parent View Controller

I have a View Controller "VCInicio", that has a TableView in his View, the Cells for that TableView are in a .xib format, the cells has a custom class called "CustomiseTableViewCell", inside there I have logic that gets and print a String (Phone Number) every time I click on a RadioButton, it prints its Phone Number, I'm able to print the value (From CustomiseTableViewCell Class) and see the value on console, but I need to send that value back to "VCInicio" so I can manipulate it from that Controller. I've seen lots of examples that suggest to use Protocols but I haven't been able to make them work.
EDIT: Because of the structure I'm using, I can't work with didSelectRowAt, hence I'm working with the Selection of the Radio Button instead of the selection of the cell.
What Fixed the Issue:
"CustomiseTableViewCellDelegate" TableView Custom Class (Child Class)
//Protocol Implementation
protocol CustomiseTableViewCellDelegate {
func onPhoneNumberClicked(_ cell: CustomiseTableViewCell, phoneNumber: String?)
}
class CustomiseTableViewCell: UITableViewCell {
var delegate: CustomiseTableViewCellDelegate?
var phone: String?
override func awakeFromNib() {
super.awakeFromNib()
...
}
//Here I get and send the phoneNumber
#objc func radioButtonTapped(_ radioButton: UIButton) {
...
phone = itemLabel.text!
self.delegate?.onPhoneNumberClicked(self, phoneNumber: phone!)
...
}
}
"VCInicio" View Controller
class VCInicio: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomiseTableViewCellDelegate {
func onPhoneNumberClicked(_ cell: CustomiseTableViewCell, phoneNumber: String?) {
//Here I print the phoneNumber
print("From VCInicio", phoneNumber)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "phoneCell", for: indexPath) as! CustomiseTableViewCell
cell.delegate = self
...
//cell data config
...
return cell
}
}
If you don't want to use custom protocols:
Assuming you have the numbers stored in some model in variable phoneNumbers: [String]
Make your VC table view delegate:
self.tableView.delegate = self
Extend ViewController to conform UITableViewDelegate protocol
class VCInicio: UIViewController, UITableViewDelegate {
//...
}
Implement func tableView(UITableView, didSelectRowAt: IndexPath) and use selected cell phone value to manipulate it later
class VCInicio: UIViewController, UITableViewDelegate {
//...
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedPhoneNumber = self.model.phoneNumbers[indexPath.row]
// manipulate selectedPhoneNumber
}
}
With protocols:
Define cell delegate and use it in the method for click
protocol CustomiseTableViewCellDelegate: class {
func onPhoneNumberClicked(_ cell: CustomiseTableViewCell, phoneNumber: String?)
}
class CustomiseTableViewCell: UITableViewCell {
weak var delegate: CustomiseTableViewCellDelegate?
// ... rest of your cell class
func onPhoneClicked() {
// this is the function where you have code to print the number to console
print(self.phoneNumberLabel.text)
self.delegate?.onPhoneNumberClicked(self, self.phoneNumberLabel.text)
}
}
In your UITableViewDataSource method for creating cells make VCInicio as cell's delegate
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// assuming you have your cell here
cell.delegate = self
return cell
}
Make your VC conform to CustomiseTableViewCellDelegate protocol
class VCInicio: UIViewController, CustomiseTableViewCellDelegate {
//...
override func onPhoneNumberClicked(_ cell: CustomiseTableViewCell, phoneNumber: String?) {
// manipulate phoneNumber
}
}
This code below is right now for an ImageView with a gesture recognizer. Which is targeted to the handleAvatarTap. Which is posting a global notification. Any ViewController or View can listen to notifications, and once the chosen one is posted the controller can act on this.
In the example below is an example, passing the ImageView as an object for the notification.
// this is how I am creating a new notification name type
extension Notification.Name {
static let didTapAvatar = Notification.Name("didTapAvatar")
}
// this would go within the cell where you are printing the number
#objc func handleAvatarTap() {
NotificationCenter.default.post(name: .didTapAvatar, object: self)
}
// This would go in to the view controller viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(handleAvatarTap), name: .didTapAvatar, object: nil)
// This is the objc func within the view controller
#objc fileprivate func handleAvatarTap(notification: NSNotification) {
// checking the type of the posted notification object
guard let avatarView = notification.object as? AvatarView else { return }
}

Click on UIButton outside table view change in tableview cell text

I am new in IOS and i want to create a table view and a UIButton outside from tableView in swift.
I want to click on a UIButton and then change text of UITableViewCell.
I would create new UIViewController. In this view controller create UITableView property and UIButton property and in init of view controller I would create new UITableView and assign to this property, same for UIButton.
Implement tableViewDelegate and tableViewDatasource methods.
In viewDidLoad() you need to make some layouting. For example fit table view in first half, and button under table view.
In button action you can change your dataModel on which tableView is rendered. (In method cellForRowAtIndexPath)
After all you need is call tableView.reloadData() and method cellForRowAtIndexPath is triggered and re-render table based on updated datamodel.
Minimal code example
In this code example, UIButton is not under tableView and is in navigationBar. Also whole controller is subclass of UITableViewController instead of adding tableView to UIViewController. I just want to make it simple as possible.
//
// MasterViewController.swift
// stackOverflow
//
// Created by Jakub Prusa on 14.07.17.
// Copyright © 2017 Jakub Prusa. All rights reserved.
//
import UIKit
class MasterViewController: UITableViewController {
var dataModel = ["AAA","BBB","CCC","DDD",]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(modifyDataModel(_:)))
navigationItem.rightBarButtonItem = addButton
}
// MARK: - Button action
func modifyDataModel(_ sender: Any) {
dataModel[2] = "xx_CCC_xx"
tableView.reloadData()
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataModel.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel!.text = dataModel[indexPath.row]
return cell
}
}

How can I segue from UICollectionView's cells embedded inside UITableViewCell (Swift)?

I have used this tutorial to successfully embed a UICollectionView inside a UITableView I have in my ViewController.
The following will probably make more sense if you have a quick look at the linked tutorial's code (plus its a nifty thing to learn too!):
The next step for me is to perform segues from the cells of the UICollectionView inside the UITableViewCells of the tableView, but as the collectionView outlet is established in a separate View Controller, I am not sure how to reference it in the main ViewController.
In the TableViewCell.swift there is:
class TableViewCell: UITableViewCell {
#IBOutlet private weak var collectionView: UICollectionView!
}
extension TableViewCell {
func setCollectionViewDataSourceDelegate<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>(dataSourceDelegate: D, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row
collectionView.reloadData()
}
}
And in the ViewController.swift I need to be able to, for instance, call the collectionView that is in the TableViewCell in the prepareForSegue function that would go in the ViewController.swift file. I just need to fill the gaps with the collectionView outlet:
let destination = segue.destinationViewController as! SecondViewController
let indexPaths = self.___________.indexPathsForSelectedItems()
let indexPath = indexPaths![0] as NSIndexPath
let arrayObject = self.arrayObjects[indexPath.row]
destination.object = arrayObject
'object' is implemented in SecondViewController like so, var object: PFObject!.
I now need to fill the gap, ________, in the above code with the collectionView in order to display the correct 'object' in SecondViewController (the destinationViewController)
Add Push Segue from UICollectionViewCell to YourViewController from IB.
Give an identifier to your segue ("YourSegueIdentifier").
In your custom UITableViewController or UIViewController, override prepareForSegue() method.
This is:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourSegueIdentifier" {
if let collectionCell: YourCollectionViewCell = sender as? YourCollectionViewCell {
if let collectionView: UICollectionView = collectionCell.superview as? UICollectionView {
if let destination = segue.destination as? YourViewController {
// Pass some data to YourViewController
// collectionView.tag will give your selected tableView index
destination.someObject = tableObjects[collectionView.tag].someObject
destination.productId = collectionCell.product?.id
}
}
}
}
}
Hi I had the same problem
This is what I did :
1. set a tag for the cell in the extension in your first View Controller
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("advertisementCollectionCell",forIndexPath: indexPath) as! AdvertisementCollectionViewCell
// set your cell information
cell.tag = indexPath.row
return cell
}
2. Do a segue on the storyboard from the UIcollectionViewCell to the new View Controller
3. In prepareForSegue of the first TableViewController :
else if segue.identifier == "identifier"
{
let destinationViewController = segue.destinationViewController as! DestinationViewController
if let cell = sender as? MyCollectionViewCell
{
let indexPath = cell.tag
// use indexPath :D
}
}
i just played with the code you attached. i added segue in story board manually. its easy to call .
1) just add viewcontroller to the storyboard.
2) Controll+ drag and drop segue from collectionview cell
In your code, the reference to CollectionView is connected in TableViewCell.
So, you can refer it through TableViewCell and set datasource and delegate.
To add connect into your code, you have to select the CollectionView with RightButton and drag and drop into #IBOutlet private weak var collectionView: UICollectionView!
When clicks the CollectionViewCell, collectionView(collectionView:UICollectionView, didselecteditemAtIndexPath indexPath: NSIndexPath) function of UICollectionViewDelegate will be called by delegate.
At that time, you can segue by calling performSegue in this function.
As you write in your code, the index of tableview is set by tag, so you can get the index by tag using collectionView.tag()
The code will be as following.
var tableViewIndex = collectionView.tag()
So you can refer the correct cell using tableViewIndex and indexPath.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
var tableViewIndex = collectionView.tag;
self.performSegueWithIdentifier("segueIdentifier", sender: self)
}

UITableview with more than One Custom Cells with Swift

I want to use a UITableview with different custom tableViewCells. My 3 cells are as such:
Cell1: should have an image and a label.
Cell2: should have two labels.
Cell3: should have a dayPicker.
I don't want to code a tag for the cells. How can I manage this in Swift. Do I have to code my own class for every cell? Can I use one tableviewController? How can I populate data in different cells?
I would like to generate a tableView, like a contact app of an iOS device.
Let me start with answering your questions first.
Do I have to code an own class for every cell?=> Yes, I believe so. At least, I would do that way.
Can I use one tableviewController?=> Yes, you can. However, you can also have a table view inside your View Controller.
How can I populate data in different cells? => Depending on the conditions, you can populate data in different cells. For example, let's assume that you want your first two rows to be like the first type of cells. So, you just create/reuse first type of cells and set it's data. It will be more clear, when I show you the screen shots, I guess.
Let me give you an example with a TableView inside a ViewController. Once you understand the main concept, then you can try and modify anyway you want.
Step 1: Create 3 Custom TableViewCells. I named it, FirstCustomTableViewCell, SecondCustomTableViewCell, ThirdCustomTableViewCell. You should use more meaningful names.
Step 2: Go the Main.storyboard and drag and drop a TableView inside your View Controller. Now, select the table view and go to the identity inspector. Set the "Prototype Cells" to 3. Here, you just told your TableView that you may have 3 different kinds of cells.
Step 3:
Now, select the 1st cell in your TableView and in the identity inspector, put "FirstCustomTableViewCell" in the Custom class field and then set the identifier as "firstCustomCell" in the attribute inspector.
Do the same for all others- Set their Custom Classes as "SecondCustomTableViewCell" and "ThirdCustomTableViewCell" respectively. Also set the identifiers as secondCustomCell and thirdCustomCell consecutively.
Step 4: Edit the Custom Cell Classes and add outlets according to your need. I edited it based on your question.
P.S: You need to put the outlets under the class definition.
So, In the FirstCustomTableViewCell.swift, under the
class FirstCustomTableViewCell: UITableViewCell {
you would put your label and image view outlets.
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var myLabel: UILabel!
and in the SecondCustomTableViewCell.swift, add the two labels like-
import UIKit
class SecondCustomTableViewCell: UITableViewCell {
#IBOutlet weak var myLabel_1: UILabel!
#IBOutlet weak var myLabel_2: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
and the ThirdCustomTableViewCell.swift should look like-
import UIKit
class ThirdCustomTableViewCell: UITableViewCell {
#IBOutlet weak var dayPicker: UIDatePicker!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Step 5: In your ViewController, create an Outlet for your TableView and set the connection from storyboard. Also, you need to add the UITableViewDelegate and UITableViewDataSource in the class definition as the protocol list.
So, your class definition should look like-
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
After that attach the UITableViewDelegate and UITableViewDatasource of your table view to your controller. At This point your viewController.swift should look like-
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
P.S: If you were to use a TableViewController rather than a TableView inside a ViewController, you could have skipped this step.
Step 6: Drag and drop the image views and labels in your cell according to the Cell class. and then provide connection to their outlets from storyboard.
Step 7: Now, write the UITableViewDatasource's required methods in the view controller.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "firstCustomCell")
//set the data here
return cell
}
else if indexPath.row == 1 {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "secondCustomCell")
//set the data here
return cell
}
else {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "thirdCustomCell")
//set the data here
return cell
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Swift 3.0 + update with minimum code
Basic concept:
Create a table view with dynamic cell prototypes. Assign identifier and create custom table view cell class for each cell prototype. Initiate and show custom cells in table view's delegate method.
1. Create cells on storyboard
Drag a tableView to your view controller, add prototype cells to it, and then drop UI element to your table view cells, add constraint properly if needed.
2. Create custom UITableViewCell classes
Add the following code to your project. I am putting it right above the view controller class.
class FirstTableCell: UITableViewCell {
}
class SecondTableCell: UITableViewCell {
}
class ThirdTableCell: UITableViewCell {
}
3. Assign custom class and identifier to cell prototypes
For each of the cell prototypes in storyboard, assign the custom class created from step 2, and then enter an unique identifier.
4. Connect UI elements to swift code
Control drag the table view and connect to the view controller class. Control drag the UI elements that get added to cell prototypes on step 1, and connect to the corresponding table view cell class.
5. Add code to view controller and control the table view
Make your view controller conform to table view delegate
class YourViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
In viewDidLoad, set up table view's delegate and data source.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
self.tableView.delegate = self
}
Finally, add two delegate methods to control your table view, as per minimum requirement.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "firstTableCell") as! FirstTableCell
// Set up cell.label
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "secondTableCell") as! SecondTableCell
// Set up cell.button
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "thirdTableCell") as! ThirdTableCell
// Set up cell.textField
return cell
}
}
6. Give it a try :)
I recommend to use this simple and easy to use library, I made for Table and Collection views. You can add as many types of cells as you want and achieve more clean ViewControllers without boilerplate code.
https://github.com/deniskakacka/DKDataSources
For UI on first picture, all your code in ViewController is this:
lazy var dataSource = DKTableDataSource<CellType>(
models: [
DisclosureCellModel(title: "Disclosure 1", action: .action1),
TextFieldCellModel(title: "TextField 1", placeholder: "Placeholder 1"),
SwitchCellModel(title: "Switch 1", isOn: true),
BannerCellModel(imageName: "placeholder"),
SwitchCellModel(title: "Switch 2", isOn: false),
BannerCellModel(imageName: "placeholder"),
DisclosureCellModel(title: "Disclosure 2", action: .action2),
TextFieldCellModel(title: "TextField 2", placeholder: "Placeholder 2"),
BannerCellModel(imageName: "placeholder")
]
)
// in `viewDidLoad`
dataSource.registerCells(for: tableView)
tableView.dataSource = dataSource
Swift 5
Create 3 Custom TableViewCells. I named it,
FirstTableViewCell, SecondTableViewCell,
ThirdTableViewCell
Add All 3 Custom Cell Classes and add outlets according to your need.
I have added in below code.
class FirstTableViewCell: UITableViewCell {
#IBOutlet weak var myImageView: UIImageView!
#IBOutlet weak var myLabel: UILabel!
static let cellIdentifier = "FirstTableViewCell"
static let cellNib = UINib(nibName: "FirstTableViewCell", bundle: Bundle.main)
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
}
}
3: In your ViewController, create an Outlet for your TableView. Also, you need to add the UITableViewDelegate and UITableViewDataSource in the class definition.
#IBOutlet weak var tableView: UITableView! {
didSet {
tableView.delegate = self
tableView.dataSource = self
tableView.register(FirstTableViewCell.cellNib, forCellReuseIdentifier: FirstTableViewCell.cellIdentifier)
tableView.register(SecondTableViewCell.cellNib, forCellReuseIdentifier: SecondTableViewCell.cellIdentifier)
tableView.register(ThirdTableViewCell.cellNib, forCellReuseIdentifier: ThirdTableViewCell.cellIdentifier)
}
}
4.Now, write the UITableViewDatasource's required methods in the view controller.
extension ViewController: UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: FirstTableViewCell.cellIdentifier, for: indexPath) as? FirstTableViewCell else { return UITableViewCell() }
return cell
}else if indexPath.row == 1 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: SecondTableViewCell.cellIdentifier, for: indexPath) as? SecondTableViewCell else { return UITableViewCell() }
return cell
}else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: ThirdTableViewCell.cellIdentifier, for: indexPath) as? ThirdTableViewCell else { return UITableViewCell() }
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50 //According requirement
}
}
Your code will look like below(View Controller Code)
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView! {
didSet {
tableView.delegate = self
tableView.dataSource = self
tableView.register(FirstTableViewCell.cellNib, forCellReuseIdentifier: FirstTableViewCell.cellIdentifier)
tableView.register(SecondTableViewCell.cellNib, forCellReuseIdentifier: SecondTableViewCell.cellIdentifier)
tableView.register(ThirdTableViewCell.cellNib, forCellReuseIdentifier: ThirdTableViewCell.cellIdentifier)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension ViewController: UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: FirstTableViewCell.cellIdentifier, for: indexPath) as? FirstTableViewCell else { return UITableViewCell() }
return cell
}else if indexPath.row == 1 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: SecondTableViewCell.cellIdentifier, for: indexPath) as? SecondTableViewCell else { return UITableViewCell() }
return cell
}else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: ThirdTableViewCell.cellIdentifier, for: indexPath) as? ThirdTableViewCell else { return UITableViewCell() }
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50 //According requirement
}
}
The above answers are the best answers, but there are TONS of reasons to get this issue. Here is another potential solution for anyone with this problem:
My problem was that I was segueing to the ViewController class and not the storyboard view. So my reference to the storyboard cell was meaningless, since the storyboard wasn't being used.
I was doing this:
let viewControllerB = SubViewController()
viewControllerB.passedData = diseases[indexPath.row].name
navigationController?.pushViewController(viewControllerB, animated: true)
And I needed to do something like this:
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "SubViewStoryboardController") as! SubViewController
nextViewController.passedData = diseases[indexPath.row].name
self.present(nextViewController, animated:true, completion:nil)
Hope this helps someone.
If you're using custom XIBs as TableView Cells then follow the below code
//Write in viewDidLoad()
let nib = UINib(nibName: "PrinterTVC", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "CELL1")
let nib1 = UINib(nibName: "SelectAndEditTVC", bundle: nil)
tableView.register(nib1, forCellReuseIdentifier: "CELL2")
UITableViewController is inheriting UIViewController that already has UITableviewDataSource & UITableviewDelegate mapped on itself.
You might subclass UITableViewController or use a TableView inside your ViewController.
After that you must implement required methods(cellForRowAtIndexPath and numberOfRowsInSection) which are declared in the UITableviewDataSource.
Also in storyboard, you need to create cell prototypes with unique Id.
There are basic types of cell, with (title, subtitle for instance) - you can use them too if you don't need special configuration.
So, for picker, yes, you need to create your own custom cell. Create necessary custom UITableViewCell class holding date picker and make sure to use delegate to send back the desired result back to your ViewController.