I'm trying to embed a Table View in a regular View Controller because I want some other Views in the View Controller besides just the Table View. I had a Table View Controller with some methods that I was overriding. I copied the code for the Table View Controller, pasted it into a Table View .swift file, and removed the "override" before each method as the methods weren't inherent to the Table View class. Unfortunately I'm still getting errors in a few lines of the code:
super.viewDidLoad()
"Value of type 'UITableView' has no member 'viewDidLoad'"
tableView.rowHeight = UITableViewAutomaticDimension
"Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'"
tableView.estimatedRowHeight = 60.0
"Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'"
super.didReceiveMemoryWarning()
"Value of type 'UITableView' has no member 'didReceiveMemoryWarning'"
tableView.insertRows(at: [indexPath], with: .automatic)
"Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'"
What do I need to do to those lines of code to make my program run? It fails to build if I leave the code as it is, and if I put two slashes in front of those lines of code, it runs but just creates a black screen. Any help would be greatly appreciated! Thanks!
import UIKit
class TaskListTableView: UITableView {
var tasks:[Task] = taskData
func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
}
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
#IBAction func cancelToLoLFirstTableViewController(_ segue:UIStoryboardSegue) {
}
#IBAction func saveAddTask(_ segue:UIStoryboardSegue) {
if let AddTaskTableViewController = segue.source as? AddTaskTableViewController {
if let task = AddTaskTableViewController.task {
tasks.append(task)
let indexPath = IndexPath(row: tasks.count-1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
as! TaskCell
let task = tasks[indexPath.row] as Task
cell.task = task
return cell
}
}
I think you are confused about what the UITableView and UITableViewController classes do.
A UITableView class is the class that draws the table view component you see on your screen, updates it when necessary and interprets your taps and scrolls into something that makes sense in terms of a table. UITableView extends UIView.
The UITableViewController class is designed to manage a UITableView instance, providing data to display and responding to the actions that it generates. It is an extension of the UIViewController class.
UIView and UIViewController are completely different things and perform completely different functions. You cannot cut and paste code from one to the other because they won't understand it.
So my first recommendation is to hit the books. Read up on what UIView and UIViewController's do to get an understanding of their place in the iOS universe and how they relate to each other. Then look at UITableView and UITableViewController.
Secondly, as to your problem of wanting to have a screen with a table view as well as other components. There are multiple ways to do this and the best solution will vary depending on the complexity of the UI you are trying to build and the data and code behind it.
Once you've got your head around how views and controllers work. I would start by building a simple screen with several simple components on it and a single controller behind it. ie. A class you have written that extends UIViewController.
When your happy with this, you have two choices that I typically see:
You can add a UITableView UI component and set your UITableViewController as it's dataSource <UITableViewDataSource> and delegate <UITableViewDelegate>. Then add in the various methods from these protocols to define the data to display and how your controller will respond to your actions on the table view.
A more complex choice you should look at if #1 gets too messy. This choice can result in cleaner code. Instead of adding the UITableView UI component, you add a UIContainerView UI component. UIContainerViews are designed to link to a seperate controller and view. Effectively this means you have two controllers. One for the general UI components and one for the table view.
This is all going to depend on exactly what you are trying to do. But first you need to do some reading.
Related
If I change the orientation of the phone,I wanted to change the rowHeight of the tableview. its work in simulator not in Real Device
Anyone help me to solve this issue
Thank you
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if UIDevice.current.orientation.isLandscape{
printer.isEnabled = true
return 140
}else{
return 90
}
}
I believe the problem is with either your tableViewDelegate or with your tableViewDataSource these both have to be set to the current view controller (the table view's view controller) the Delegate is the thing which handles events such as touches etc and the dataSource places the data into the table view's rows and sections.
If you are NOT using a UITableViewController and instead are using a UIViewController with a UITableView added on it as a sub view then you need to do these two things:
(you can place this in viewDidLoad() or wherever else you feel is best, make sure to place it inside of an appropriate view controller life-cycle method or it will not be executed properly).
tableView.delegate = self
tableView.dataSource = self
An alternative to doing that is using a UITableViewController which you drag out directly from inside of interface builder (This already has the delegate and dataSource hooked up to itself therefore you do not have to set it yourself in code.):
Your code worked for me with one of those:
(Using this method also requires your view controller to inherit from UITableViewController as shown below).
class TableViewController: UITableViewController {
// Other data source methods such as cell for row at etc...
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if UIDevice.current.orientation.isLandscape{
print("row height: 140") // Test
return 140
} else {
print("row height: 90") // Test
return 90
}
}
}
Regardless of selection, I need to know the tableview involved with a mouse click. Consider
func tableViewSelectionDidChange(notification: NSNotification) {
self.selectedTableView = (notification.object as! NSTableView)
switch selectedTableView {
case oneTableView?:
print("one")
break
case twoTableView?:
print("two")
break
default:
print("wtf \(selectedTableView)")
}
}
table/view 'two' is a detail of 'one'. Selecting a row in 'one' alters the content for tableview 'two' (header -> detail). But if the user clicked a row already selected, no notification as the selection did not change. Basi I just need to know the last tableview / column clicked.
Is mouseDown approach better (way more difficult) but I do not see objective-c or 'UI' equivalent delegate methods in the AppKit -> NSTableView -> NSTableView for column or row selection methods?
What you should do is, within this UITableViewDelegate Function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let tableOne = tableView as? TableOne {// do code here to other table}
else if let tableTwo = tableView as? TableTwo {//do code here to other table}
}
Well, on osx in the current AppKit (8.2.1) state on Sierra this is not doable.
My gui is using a single action control for a set of header/detail tableViews and I needed to know which was in effect, so I'm to mandating an empty selection in the detail table view to indicate the header view selection is to be used.
But I would like to know why osx swift doesn't have a comparable delegate method set that ios or objective-c have?
I am a beginner coder in swift. I am trying to create a tabbed application. For one of my tabs, I am creating a table view which has multiple rows each which have a different task (A good way to think of this is the facebook app, where each option in the more screen will take you to a separate view)
Now, my table is populated with an array:
let array = ["one", "two", "three]
I want to ask, that everytime that I tap on one of these rows, I would like to go a new view controller. How is this possible?
What I tried was performSegue with an identifier which I give in the storyboard, but then there would be an x amount of segues connecting to the table view? So I don't think this is right? :/
I know the contents of the array prior to generating the table, so If I know the array value, and the row being tapped, how can I navigate to a new view controller?
Edit:
When performing the segue between the controllers, I am using:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "showView", sender: self)
}
This of course will only connect to the segue showView however, how can i add multiple view controllers?
You need to simply compare which row is selected in tableView and then perform segue according to it.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let segueIdentifier: String
switch indexPath.row {
case 0: //For "one"
segueIdentifier = "showView1"
case 1: //For "two"
segueIdentifier = "showView2"
default: //For "three"
segueIdentifier = "showView3"
}
self.performSegue(withIdentifier: segueIdentifier, sender: self)
}
Add the following function to your controller.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
navigationController?.pushViewController(NewController(), animated: true)
}
Using Static Cells in a UITableViewController
Summary
An alternative is to use a UITableViewController with static cells. If you know already know the menu then you can just create static cells for each item.
In the storyboard you can connect a segue from each cell to their respective view controllers.
Example
I am coding an app which has a UITableView. I currently have a segue set up set up for the cells in the table as such:
var selectedRow = Int() //global variable so it can be used in both VCs
import UIKit
class TableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "rowSelected", sender: Any?.self)
selectedRow = indexPath.row
}
}
The segue works fine. However, in the swift file that controls the viewController (only being used to change the text of a label) does not work appropriately. Here is the code from that VC:
override func viewDidLoad() {
super.viewDidLoad()
firstLabel.text = infoArray[selectedRow]
print(selectedRow)
}
The infoArray is set up correctly, but the label is not always change to the correct text... printing selectedRow returns inconsistent numbers... if I hit the first cell it will return 0 sometimes, but it also returns 1, 3, 2, etc... It seems random and isn't correctly returning the current int (and therefore the label text isn't set correctly). Why is this?
What you're doing is not the way to pass information from one view controller to another. To pass information, pass the information. Instead of dropping the information in a global, implement prepare(for:sender:), where you can get the segue's destination view controller as it prepares, and set a property of the destination view controller.
Issue
I have a single page app with a single view controller. On the screen there is a button that slides out/in a (smaller) UIView with a TableView (functions correctly). My goal is to simplify my view controller, hence my idea was to split off the UIView with the TableView into its own view controller. Therefore I've created a second view controller in the Storyboard and created a class HintsViewTableViewController, that contains the TableView datasource and delegate methods.
Main View controller
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var HintsViewTableVC = HintsViewTableViewController()
HintsViewTableViewController
class HintsViewTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var HintsViewTableView: UITableView!
#IBOutlet var hintsLabel: UILabel!
override func viewDidLoad() {
hintsLabel.text = "HINT" <---fatal error: unexpectedly found nil while unwrapping an Optional value
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 4
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return CGFloat (40)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
// Configure the cell...
cell.textLabel!.text = "\(indexPath.row)"
return cell
}
}
Problem
If the storyboard entry point is the Main View Controller, the compiler gives an error stating that my property hintsLabel! is nil and crashes.
If I move the storyboard entry point directly to the HintsViewTableViewController, then the app runs and shows the correct view on screen.
Question
Apparently, the procedure to initialize a view controller directly (using the storyboard entry point) is different from assigning the view controller to a variable (as I do in the first case). I've searched high and low for init methods, but have come up blank.
Another solution I've tried: making a separate XIB file and linking this to my HintsViewTableViewController, however TableViews in XIB files can't have prototype cells.
What am I missing here, or stated differently: what's the correct procedure to separate a UIView into a separate view controller (in the same Storyboard)?
The problem is that when you instantiate your HintsViewTableViewController like this:
var HintsViewTableVC = HintsViewTableViewController()
you are creating an instance of the class, BUT that class knows nothing about your Storyboard, so all of the #IBOutlets will be nil because they aren't wired to anything.
Instead, you need to ask the Storyboard to create the ViewController:
self.storyboard?.instantiateViewControllerWithIdentifier("hintsController") as! HintsViewTableViewController
where hintsController is the Storyboard ID you have set for that ViewController in the Identity Inspector.
Note: You will need to make this call to the Storyboard in a method (such as viewDidLoad where self will refer to an instance of your ViewController class.
If you want to declare it as a property like you were doing before, making it a lazy property will allow it to be created when first accessed (and self will be available then):
lazy var hintsViewTableVC: HintsViewTableViewController = { self.storyboard?.instantiateViewControllerWithIdentifier("hintsController") as! HintsViewTableViewController }()