I have got a viewController in storyboard with following file
import UIKit
class jokesviewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
}
}
and another controller in which i use this controller by making its object , (well this a JSQmessagesController Class in which i make object of jokesviewController class)
and the code i use is
var jokeviewController :jokesviewController? //at class begnning
and somewhere in some function
jokeviewController = jokesviewController()
self.view.addSubview(jokeviewController!.view)
jokeviewController!.view.backgroundColor = UIColor.grayColor()
my question is i get to use jokeviewController!.view giving me a view to use but when i try to get jokeviewController!.tableview it says i got a nil value .
I have tried both ways putting tableView inside a view and tableview without container view in the controller .
Any guesses
First of all, always use upper case for controllers( or classes ).
Secondly you instantiate view controller as is, but IB outlets and other stuff lives in storyboard. So, instead of
jokeviewController = jokesviewController()
use
jokeviewController = UIStoryboard(name: "yourStoryboard", bundle: nil).instantiateViewControllerWithIdentifier("giveYourViewControllerIdentifier") as! jokesviewController
and you will have everything set up.
For giving identifier for your view controller in storyboard, select your view controller in storyboard, select third tab and set storyboard ID to whatever you want.
Related
I have the following problem:
I am making a Pokédex-like application that displays a list of all 721 Pokémon on the first tab, and another list on the second tab containing My Favorite Pokémon. Essentially, there are two identical ViewControllers connected to my TabBar.
My storyboard is as follows:
So here is the problem:
The TableView on the first (and initial) tab works fine. However, when I load the TableView on the second tab the Pokémon are loaded, but not displayed. I am able to click the TableViewCell and go to the detail page, but the label in the TableViewCell is not showing anything.
This is the code I use for loading Favorites TableView
class FavoritesViewController: BaseViewController,
UITableViewDataSource, UITableViewDelegate {
#IBOutlet var FavoritesListView: UITableView!
var pokemonList: [String] = ["Nothing Here!"]
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FavoriteCell", forIndexPath: indexPath) as! FavoriteCell
var name = pokemonList[indexPath.row]
capitalizeFirstLetter(&name)
cell.nameLabel.text = name
return cell;
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pokemonList.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(pokemonList[indexPath.row])
self.performSegueWithIdentifier("ToPokemonDetail", sender: pokemonList[indexPath.row])
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "ToPokemonDetail"){
let destination = segue.destinationViewController as! PokemonDetailViewController
let thisPokemon = sender as! String
destination.currentPokemon = thisPokemon
}
}
override func viewWillAppear(animated: Bool) {
FavoritesListView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// Fetch the cached list, getNames returns an array of strings
let list = utility.getNames("Favorites")
pokemonList = list
}
The delegate and the dataSource are set via the storyboard.
The above code works, and shows the Favorites list just fine. The class for the complete Pokédex has a similar construction.
I have tried switching Favorites and Pokédex around, so that it shows the complete Pokémon list on startup. All 721 Pokémon are shown correctly, but then the Favorites are not visible.
What else I have tried:
Checking the Reuse Identifiers, over and over
Referencing outlets should be bound correctly
Calling TableView.reloadData() in the viewDidAppear method
Switching around the tab items
Does anyone have any clue what on earth is going on here?
Feel free to ask any more questions
Edit: this is what happens when I swap the two TabBar Buttons around, no code changes
Pokédex Screen
Favorites Screen
GitHub Project Here
Problem is in storyboard cell label frame. Set constraints of view controller for (Any,Any) Size Class. I can commit the code on github if you can give me write rights on your git. Thanks
Perhaps your table's delegate and dataSource are not set.
table.delegate = self
table.dataSource = self
Of course this is after you add the properties to your view controller
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
Your number of rows is always 0 for that controller,
I looked into your code pokemonList count is always 0 its not updating data in it
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pokemonList.count
}
The big issue is your PokemonDetailViewController is not a UITableViewController. It needs to inherent from UITableViewDataSource, UITableViewDelegate and then be connected to the storyboard view to provide data and formatting for a table.
I am new to Swift, and iOS development in general. I am attempting to create a custom UITableViewCell. I have created the cell in my main storyboard on top of a UITableView that is inside a UIViewController. When I loaded one of the default cells, I was able to populate it with data. However, now that I am using a custom cell, I cannot get any data to appear in the table. I have gone through all kinds of tutorials and questions posted on the internet, but I can't figure out why it is not working. Any help would be appreciated.
Here is my code for the UIViewController that the tableview resides in.
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//self.tblView.registerClass(UITableViewCell.self, forCellReuseIdentifier : "Cell")
self.tblView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier : "Cell")
tblView!.delegate = self
tblView!.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataMgr.data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : CustomTableViewCell = self.tblView.dequeueReusableCellWithIdentifier("Cell", forIndexPath : indexPath) as! CustomTableViewCell
var values = dataMgr.data[indexPath.row]
cell.newTotalLabel?.text = "\(values.newTotal)"
cell.winLoseValueLabel?.text = "\(values.newTotal - values.currentTotal)"
cell.dateLabel?.text = "5/17/2015"
return cell
}
}
I have stepped through the program where it is assigning values to the cell variables. The variable 'values' is being populated with data, but when stepping over the assignment lines to the cell variables, I found that they are never assigned. They all remain nil.
When you make a custom cell in the storyboard, don't register the class (or anything else). Just be sure to give the cell the same identifier in the storyboard that you pass to dequeueReusableCellWithIdentifier:forIndexPath:.
Why I get this error?
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: '-[UITableViewController
loadView] loaded the "pB1-re-lu8-view-o7U-YG-E7m" nib but didn't get a
UITableView.'
here is my code:
class FriendListTableViewController: UITableViewController{
var objects = NSMutableArray()
var dataArray = [["firstName":"Debasis","lastName":"Das"],["firstName":"John","lastName":"Doe"],["firstName":"Jane","lastName":"Doe"],["firstName":"Mary","lastName":"Jane"]]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let object = dataArray[indexPath.row] as NSDictionary
(cell.contentView.viewWithTag(10) as! UILabel).text = object["firstName"] as? String
(cell.contentView.viewWithTag(11) as! UILabel).text = object["lastName"] as? String
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return false
}
my storyboard is like this:
I have face same issue once upon time, and So stupid mistake it was, I have subclass the UITableViewController, where I have added UITableView in UIViewController
From your storyboard Image, it may be solved if you use UIViewController instead of UITableViewController, Just try that way can solve your issue,like
class FriendListTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
SWIFT 2 UPDATE
I tried #Viralsavaj's answer but it didn't work for me until I "hooked up" the tableView as an outlet from the storyboard in the ViewController.
like this: #IBOutlet weak var tableView: UITableView!
Also add this to your class as #Viralsavaj mentioned:
class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
I used specifically this link help as well: How to reference tableView from a view controller during a segue
Just drag your tableView into the ViewController and make it an outlet. Then you can reference its properties such as self.tableView.reloadData().
This property as well as others that referenced the tableView were giving me errors until I added the tableView as a referencing outlet.
Hope this helps those in the future.
I had this issue with Swift 2, Xcode 7.2, I changed a View Controller I dragged to my Storyboard to a custom UITableViewController class, I then dragged a Table View onto the View Controller. I didn't realize I placed it as a child of the View that was part of the original View Controller I dragged onto the Storyboard.
I simply deleted the View and added the Table View again as the first child of the Super View.
I am learning Swift and I have pattern that I used to do in Objective C, but don't understand how to do it here.
I have UIViewController with TableView. I works fine when I put my array inside it. But according to MVC I want to move my array with data to another class. And I have no idea how to do it. Everything I tried doesn't work.
Thank you!
My code, how to move tableDS outside:
import UIKit
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
//temp table data
let tableDS = ["fdf", "dfd"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableDS.count
}
let textCellIdentifier = "TableViewCell"
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: MyCell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as MyCell
let row = indexPath.row
cell.dayLabel.text = tableDS[row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
println(tableDS[row])
}
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel.text = tableDS[indexPath.row]
return cell
}
This should work.
If you want to use the MVC pattern, create a new singleton class, create the array there, then create a method returning the array.
First you need to initialize your table view with an empty array. When you load your MyViewController from another view controller in the code example below you can pass your data, and change your let tableDS = [“fdf”, “dfd”] to var tableDS = [“fdf”, "dfd"]. let is used for a constant variables.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YourMyViewControllerSequeId" {
let myViewController = segue.destinationViewController as MyViewController
var myArrayToPass = ["learn swift", "or get a life"];
myViewController.tableDS = myArrayToPass
myViewController.tableView.reloadData()
}
}
In the MVC design pattern for a table view the table view is the view object. The controller is the view controller.
The model is whatever you use to store your data.
The controller object serves as an intermediary between the model and the view.
For a simple table view the model object can be a as simple as an array. The array is the model. Thus there is no reason to store the data in a separate object.
If you really want to make your model a completely different object, create a new class. Call it MyTableViewModel. Make your MyTableViewModel class contain an array of your data. Also make MyTableViewModel conform to the UITableViewDatasource protocol. To do that, you'll have to implement several methods - in particular, cellForRowAtIndexPath.
Now in your view controller, create a MyTableViewModel object as a strong property of your view controller, install the array in it, and make it the data source of the table view.
Done.
Again, though, it's quite common to just treat a simple array as your model, and let the view controller serve up cells by implementing cellForRowAtIndexPath in the view controller.
I have a table view controller with cells. on clicking a cell I load another view controller and I want to handle elements on this view controller. on the detail view controller I placed a label and in the first step I want to set the text of the label, but I get an exception fatal error: unexpectedly found nil while unwrapping an Optional value and I don't know why. Are there any solutions?
This is the part of my table view controller on clicking a cell:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vcMissionDetail : ViewControllerMissionDetail = self.storyboard?.instantiateViewControllerWithIdentifier("MissionDetail") as ViewControllerMissionDetail;
//load detail view controller
self.presentViewController(vcMissionDetail, animated: true, completion: nil)
//set label text
//at this line I get the exception -> label is nil
vcMissionDetail.label.text = "Test"
}
And this is my detail view controller (very simple):
import UIKit
class ViewControllerMissionDetail: UIViewController {
#IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
THX!
instantiateViewControllerWithIdentifier returns an optional because it may fail due to several reasons. So you should better unwrap it conditionally:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let vcMissionDetail : ViewControllerMissionDetail = self.storyboard?.instantiateViewControllerWithIdentifier("MissionDetail") as ViewControllerMissionDetail {
//set label text before presenting the viewController
vcMissionDetail.label.text = "Test"
//load detail view controller
self.presentViewController(vcMissionDetail, animated: true, completion: nil)
}
}
Further things to double check:
Is ViewControllerMissionDetail set as the custom class for your viewController in the identity inspector in InterfaceBuilder?
If the vcMissionDetail is successfully instantiated and it still crashes then delete the label's outlet connection in InterfaceBuilder and recreate it.
I think the solution to your problem is pretty straight forward. If I'm understanding correctly, you want to change the label on your detail view controller when you segue from table view controller using the didSelectRowAtIndexPath.
The place where you are probably making a mistake is, you're trying to change the label in your detail view controller from the table view controller.
The correct approach to your problem would be to set the label text in the 'viewDidLoad' or 'viewDidAppear' method of the detail view controller.
override func viewDidLoad() {
super.viewDidLoad()
//set label text here
}
override func viewDidAppear() {
super.viewDidLoad()
//OR set label text here
}
For swift:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showItemDetail", sender: tableView)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showItemDetail" {
let indexPath:NSIndexPath = self.tableView.indexPathForSelectedRow()!
let detailVC:ItemDetailViewController = segue.destinationViewController as ItemDetailViewController
detailVC.item = items[indexPath.row] as Item
}
}