I made basic tableView inside ViewController and while loading I get
fatal error: unexpectedly found nil while unwrapping an Optional value
Which points to tableView.delegate = self (by points to I mean this line is highlighted in green colour in Xcode). Here's full code:import UIKit
import UIKit
class FAQViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UINavigationControllerDelegate, SWRevealViewControllerDelegate {
#IBOutlet var menuButton: UIBarButtonItem!
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
if revealViewController() != nil {
//I have SWRevealController that slides viewController from Left side
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FAQ") as! FAQTableViewCell
cell.questionLabel.text = "Here goes Question"
cell.answearLabel.text = "This is answear"
return cell
}
}
From what I can see from your example, you look to be setting things up using a storyboard, but since the class is a UIViewController and not a UITableViewController, I think your connections are not wired up correctly.
I would check in the debugger to make sure tableView is not nil and to check in the storyboard to make sure that the connections look OK.
You can also wire up the tableViews dataSource and delegate in storyboard by right clicking on the tableView, and then dragging from the circle across from dataSource or delegate to the view controller associated with your storyboard scene (i.e. the first icon in the hierarchy right below the scene name in the storyboard file).
Happy to clarify if this does not make sense...
Check the following:
check your cell reuse identifier specified in the .storyboard, Xib, or in code, and ensure that it is correct when dequeuing.
otherwise it will give fatal error, the app crashes.
You have declared the tableView as implicitly unwrapped. That means this has to be initialized before assigning value to this. I guess you have just declared the tableView but not wired to the story board.
I you do not want that way declare it as optional and initialize it before setting the datasource and delegate.
Related
As far as I can tell, I have set up everything correctly (register and dequeue). However, when I try and access outlets in awakeFromNib(), I get
'Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file ....MechEntryCell.swift, line 18'
Which is weird, since other UITableViewCells doing similar things seem to work fine - and look identical to me.
The code failing:
class MechEntryCell: UITableViewCell {
#IBOutlet weak var mechName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
mechName.text = "Hello" <<<<<<< CRASHES
}
func setDamageOption(_ damageOption: AdditionalDamageOption) {
mechName.font = UIFont.boldSystemFont(ofSize: mechName.font.pointSize)
mechName.text = damageOption.label <<<< WORKS FINE IF ABOVE CRASH REMOVED
}
}
which has a .xib file where the label has been correctly linked:
And I also register and dequeue:
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: MechEntryCell, bundle: nil), forCellReuseIdentifier: "MechEntryCell")
........
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tempDamageOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: MechEntryCell.identifier) as? MechEntryCell {
cell.setDamageOption(tempDamageOptions[indexPath.item])
return cell
}
return UITableViewCell()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
Special Note:
When I set the label in the tableView(cellforRowAt:) method, then it works fine - so the IBOutlet DOES eventually link. What am I doing wrong?
Just want to add another example that might easily/accidentally happen to someone. In this case, had accidentally put the cell class on the ContentView, (rather then should have been left as simply UIView). In code, the cell's awakeFromNib was getting called twice. The first time the outlets were set, and in the second mysterious call, the outlets were nil.
I come back in shame with the solution.
somewhere during setup, I accidentally set the root view's custom class to that of the MechEntryCell. Removing this solved the issue.
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'm trying to change the text of a UILabel in a UITableView (a property of one class,) from inside another class, but I'm having trouble. The code looks like this (The problem is at the end, in the didSelectRowAtIndexPath method of myDataSource)
The View Controller
class ViewController: UIViewController
{
//MARK: Properties
#IBOutlet weak var myTableView: UITableView!
#IBOutlet weak var myLabel: UILabel!
//needed so data from myDataSource is retained by ViewController and not just thrown away
let importedDataSource = myDataSource()
override func viewDidLoad()
{
super.viewDidLoad()
myTableView.dataSource = myDataSource()
myTableView.delegate = myDataSource()
}
override func didReceiveMemoryWarning()
{super.didReceiveMemoryWarning()}
}
The UITableViewDataSource and Delegate
class myDataSource: NSObject, UITableViewDataSource, UITableViewDelegate
{
let cellIdentifier = "myTableViewCell"
let myArray = ["Label one", "Label two", "Label three"]
//MARK: TableViewDataSource
func numberOfSectionsInTableView(tableView: UITableView) -> Int
{return 1}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{return myArray.count}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! myTableViewCell
cell.myCellLabel.text = myArray[indexPath.row]
return cell
}
//MARK:TableView Delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
//This Line Here returns the error
ViewController().myLabel.text = "test"
//I want the end product to be ViewController().myLabel.text = myArray[indexPath.row], but left it as "test" just to simplify and isolate the error
}
}
(there's also a UITableViewCell class called myTableViewCell, but I left it out to be shorter)
Running returns "fatal error: unexpectedly found nil while unwrapping an Optional value" upon selecting one of the rows. How should I call myLabel so as to avoid this problem? I've tried hooking it up as an #IBOutlet inside myDataSource by ctrl-dragging it from the storyboard, but as I expected, it only lets me connect it to the view controller.
sorry, the code is a bit confusing with the two similarly named labels. I'm trying to call the myLabel var created in the ViewController (first piece of code), not the myCellLabel created in myTableViewCell (not shown)
The reason you are seeing the message "fatal error: unexpectedly found nil while unwrapping an Optional value" is because you are trying to assign a value to a property of nil.
In the implementation of your UITableViewDelegate method tableView(_:didSelectRowAtIndexPath:) the statement:
ViewController().myLabel.text = "test"
creates a new instance of your ViewController class (that is what ViewController() does)
accesses the myLabel property of the new instance (recall that in your declaration of the class you defined this property to be of type UILabel!, an implicitly-unwrapped optional UILabel, and implicitly-unwrapped optionals begin life as nil until they are assigned a value)
tries to assign "test" to the text property of myLabel - but as we just noted, myLabel is nil and this is why you are receiving the error message
EDIT
In an effort to assist you in your stated goal of "trying to change the text of a UILabel" (that label being the property myLabel of your ViewController instance), the route I would recommend is:
have your ViewController class adopt the UITableViewDelegate protocol
implement your UITableViewDelegate protocol methods inside of your ViewController class, where they will have direct access to the myLabel property
once you've done this, your implementation of that delegate method (now residing inside of your ViewController class) would look like:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
myLabel.text = myTableView.dataSource.myArray[indexPath.row]
}
...and while this will work, even this can be improved - I recommend you check out Apple's Table View Programming Guide
furthermore, unless there is a compelling reason not to, I also recommend that you have your ViewController class act as your UITableViewDataSource - from the Table View Programming Guide: "[t]he class creating the table view typically makes itself the data source and delegate by adopting the UITableViewDataSource and UITableViewDelegate protocols" (see this section)
You need to get the actual table view cell that was tapped in order to access it's variables. Use cellForRowAtIndexPath. It'll look something like this:
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
if let myCell = tableView.cellForRowAtIndexPath(indexPath) as? myTableViewCell {
myCell.myLabel.text = "test"
}
}
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.