Why presentViewController calls viewDidLoad again? - ios

I have ViewController, built using storybard and it contains a UITableView. When UITableViewCell is pressed, I just want to present SomeViewController. In didSelectRowAt method I do following:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
present(SomeViewController(), animated: true)
}
But I checked using debugger, this calls viewDidLoad in ViewController. Here is my viewDidLoad in ViewController:
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
myTableView.dataSource = self
myTableView.delegate = self
}
And Xcode throws an error that myTableView is nil here. What can be reason for this? Seems like I don't know some well known concept in iOS development. It seems like it is not possible to present a SomeViewController from ViewController without segues, because ViewController was completely built using Storyboard, when SomeViewController does not have any storyboard. So, seems like, it is not possible to combine. Another idea is that it is just a Xcode bug. So, what is the reason for the error?
UPDATE:
Here is my ViewController:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
myTableView.dataSource = self
myTableView.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Hello"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
present(SomeViewController(), animated: true)
}
}

The tableView outlet is nil because your're creating instance of SomeViewController using init like SomeViewController(). This won't connect the outlets in your controller.
Instead create the instance of SomeViewController using the storyboard, i.e.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let controller = self.storyboard?.instantiateViewController(withIdentifier: "SomeVC") as? SomeViewController {
self.present(controller, animated: true, completion: nil)
}
}
Don't forget to set the StoryboardID of SomeViewController as SomeVC in storyboard.

The reason was that I accidentally inherited SomeViewController from ViewController. Not UIViewController. Just ViewController. That of course forced to call viewDidLoad. Will never use default ViewController name.

Related

Swift: TableView (inside cell) is not loading cells or code inside cellForRowAt

Why isn't my cell loading data from a tableview inside a cell?
Basically, it runs the numberOfRowsInSection function. However, the cellForRowAt function is completely ignored and never run.
I can assure you that all my cells are properly linked up, my tableview inside the cell is delegated, and so is the root tableview (I know this as I have other data in the root tableview cell which loads properly).
Would anyone know why the code inside this function doesn't run at all?
import Foundation
import UIKit
class SettingsTable: UITableViewCell, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var myTableView: UITableView!
#IBOutlet weak var tableIcon: UIImageView!
#IBOutlet weak var tableTitle: UILabel!
var TableViewSettingsStruct = SettingsStruct()
func displayContent(tableViewTitle: String, tableViewIcon: UIImage, settingsStruct: SettingsStruct){
tableTitle.text = tableViewTitle
tableIcon.image = tableViewIcon
TableViewSettingsStruct = settingsStruct
}
override func awakeFromNib() {
super.awakeFromNib()
//Initialization
myTableView.delegate = self
myTableView.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
myTableView.delegate = self
myTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableViewSettingsStruct.cellType.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("Running tableView Code")
let cell = tableView.dequeueReusableCell(withIdentifier: "errorCell") as! UITableViewCell
cell.textLabel?.text = "An error occurred fetching the cell"
return cell
}
}
If you notice, I have added a print inside the cellForRowAt function. Unlike other tableViews I have implemented, this print statement is not displayed on the console (i.e. it's not run).
Ok thank you everyone for you help!
I figured out that my tableView had no height constraint set, and once I did set it, the tableView loaded the cell (and therefore the cellForRowAt function).
Sometimes, it can be quite tedious :/

Go to the ViewController by clicking on the TableView cell in swift

there is a class MenuViewController in which the array recorded in the table is recorded:
import Foundation
import UIKit
class MenuViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var menuTableView: UITableView!
let myTitle = ["Помощь", "Информация", "Поддержка"]
override func viewDidLoad() {
super.viewDidLoad()
menuTableView.delegate = self
menuTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myTitle.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = menuTableView.dequeueReusableCell(withIdentifier: "MenuCell") as! MenuTableViewCell
cell.labelText.text = myTitle[indexPath.row]
return cell
}
}
What do you need to write in it to go to Info Controller?
I assume you are using storyboards. First you need to set up some sort of connection between your two viewcontrollers. You can do this by setting up a "segue". You hold ctrl+click drag from the first viewcontroller to the 2nd viewcontroller. It looks like this:
When you let go of the mouse, you will see this:
Click on Show. Now you will have created a segue.
Now you need to name it. So click on the segue that shows up in the storyboard. It is basically just an arrow from the Menu View Controller to the Info View Controller. On the right hand side you will see a place where you can name it (give it an identifier):
Now ... you have done all you needed to do in the storyboard. Now in your actual code in the MenuViewController, you need to associate clicking the tableviewcell. You do this by using the delegate method didSelectRowAt.
I see you have already set up the delegate with this line:
menuTableView.delegate = self
That ensures that didSelectRowAt will be called whenever the user taps on a row.
So now what you want to do is write the code to perform the segue:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "YourSegueName", sender: self)
}
Note:
Here is more information on interacting with a tableview row:
How to detect tableView cell touched or clicked in swift
Here is more information about segues:
IOS - How to segue programmatically using swift
There are many more customizations you can do ... such as passing data through to the next viewcontroller via the segues. Here's how:
Pass data through segue
implement UITableViewDelegate method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//To InfoViewController I am considering you have created InfoViewController with XIB
let controller = InfoViewController(nibName: "YourNibName", bundle: nil)
//Present Your Controller
self.present(controller, animated: true) {
}
//Push Your controller if your view is already part of NavigationController stack
self.navigationController?.pushViewController(controller, animated: true)
}
Just add a
nextViewController.didMove(toParentViewController: self) inside a
"didSelectRowAt". Example given below.
This is for List a tableview cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! PatientFamilyDetailTableViewCell
cell.txt_patientName.text = patientname[indexPath.row]
// Configure the cell...
return cell
}
Now it's for Select a Table view cell:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
if cell.isSelected {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "medtestmain") as! medTest
patient_id = relation[indexPath.row]
patient_name = patientname[indexPath.row]
UserDefaults.standard.set(patient_id, forKey: "patient_id")
UserDefaults.standard.set(patient_name, forKey: "patient_name")
self.addChildViewController(nextViewController)
nextViewController.view.frame = self.view.frame
self.view.addSubview(nextViewController.view)
nextViewController.didMove(toParentViewController: self)
}
}
}

Finding Which Cell Was Clicked and Performing Segue

I've populated a UITableView with names of restaurants using Google Places API. Now, I am trying to perform a segue to a different view while knowing which cell was clicked with IndexPath. I've tried using the didSelectAtIndexRowPath function but it's not recognizing the tap/click. It should print out the number to the console. What am I doing wrong?
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var myIndex = 0
#IBOutlet var restuarantsTable: UITableView!
var restaurantsList = [NSDictionary]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
restuarantsTable.dataSource = self
let url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=26.2034071,-98.23001239999996&radius=500&type=restaurant&keyword=tacos&key=AIzaSyBRQZV4SOpcJ-icCe9BuZlI48MzONwH5Dw"
downloadRestaurants(urlString: url) { (array) -> () in
self.restaurantsList = array as! [NSDictionary]
// print(self.restaurantsList.count)
self.restuarantsTable.reloadData()
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return restaurantsList.count
}
#available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let RCell = tableView.dequeueReusableCell(withIdentifier: "RCell", for: indexPath)
// let imgURL = NSURL(string: imgURLArray[indexPath.row])
// let imageView = RCell.viewWithTag(350) as! UIImageView
RCell.textLabel!.text = restaurantsList[indexPath.row]["name"] as? String
// RCell.imageView?.image = restaurantsList[indexPath.row]["photos"] as? UIImage
return RCell
}
private func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
self.performSegue(withIdentifier: "detailSegue", sender: indexPath)
print(restaurantsList[indexPath.row])
}
}
You would have to conform to UITableViewDelegate like you did for UITableViewDataSource, didSelectRowAtIndexPath is a UITableViewDelegate method
Add these lines
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
And in viewDidLoad
restuarantsTable.delegate = self
I think you would have to set delegate in storyboard as well
Go to this tab and ctrl+Drag to the viewcontroller to set it as delegate
Swift 3
Error1:
You have to add UITableViewDelegate protocol for using UITableView delegate methods.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{}
In viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
restuarantsTable.dataSource = self
restuarantsTable.delegate = self
}
Error 2:
The protocol must be confirm with public. You declared as private
change
private func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath){}
to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
or (below swift 3)
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath){}
Modify two things in your code set restuarantsTable.delegate = self and then reload your table on main thread as you are making network call which will handle in background thread. So also modify below code.
DispatchQueue.main.async({
self.restuarantsTable.reloadData()
})

Swift 3 My tableView is not populatinG?

I am wondering why is my tableview not populating? I have a tableview inside my view controller and I have tried to follow the guide however, nothing seems to show up on my tableview.
here's my code
#IBOutlet weak var weatherTableView: UITableView!
var items: [String] = ["Sunny", "Cloudy", "Rainy"]
override func viewDidLoad() {
super.viewDidLoad()
self.weatherTableView.register(UITableViewCell.self, forCellReuseIdentifier: "WeatherCell")
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.weatherTableView.dequeueReusableCell(withIdentifier: "WeatherCell")! as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
am I missing something here?
Thanks for your help in advance
Make sure you are assigning tableview delegate and datasource throw storyboard or add below line into your viewDidLoad() of your viewcontroller (UITableViewDelegate, UITableViewDataSource)
weatherTableView.delegate = self;
weatherTableView.dataSource = self

Pass variable from one ViewController to another

I have an array: var initialArray. That appends every time the screen is tapped. This is done on ViewController 3
I have a table which displays the array in another view controller: ViewController2.
However the issue is: use of unresolved identifier: initialArray.
How can I get ViewController2 to recall variables from ViewController3?
class ViewController2: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
//How many rows
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return initialArray
//////use of unresolved identifier: initialArray
}
//What goes in each cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
print(indexPath.row)
cell.textLabel?.text = initialArray[indexPath.row]
//////use of unresolved identifier: initialArray
return cell
}

Resources