Simple UITableView in Swift - unexpectedly found nil
When you create a view in code, its IBOutlet
properties don't get hooked up properly. You want the version that you get back from dequeueReusableCellWithIdentifier
:
let cell = tableView.dequeueReusableCellWithIdentifier("BookCell") as BookTableViewCell
Swift UITableView reloadData() method unexpectedly found nil error
It looks like you are assigning ViewController
class to both your first controller (which holds the table view) AND to your second controller (with the text field).
That's not going to work.
Add this class to your project, assign it as the "New Item" view controller's Custom Class, and connect the @IBOutlet
and @IBAction
:
class NewItemViewController: UIViewController {
// callback closure to tell the VC holding the table view
// that the Add button was tapped, and to
// "send back" the new text
var callback: ((String) -> ())?
@IBOutlet weak var textField: UITextField!
@IBAction func add(_ sender: Any) {
let item: String = textField.text!
callback?(item)
textField.text = ""
}
}
Next, change your ViewController
class to the following:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var editButton: UIBarButtonItem!
var tableViewData = ["Apple", "Banana", "Orange", "Peach", "Pear"]
override func viewDidLoad() {
super.viewDidLoad()
// if you're not already seeing "Apple", "Banana", "Orange", "Peach", "Pear"
// add these two lines
//tableView.dataSource = self
//tableView.delegate = self
}
// MARK: Tableview methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableViewData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = tableViewData[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// print(tableViewData[indexPath.row])
}
// Allows reordering of cells
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
// Handles reordering of cells
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let item = tableViewData[sourceIndexPath.row]
tableViewData.remove(at: sourceIndexPath.row)
tableViewData.insert(item, at: destinationIndexPath.row)
}
// Allow the user to delete cells
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
tableViewData.remove(at: indexPath.row)
tableView.reloadData()
}
}
// MARK: IBActions
@IBAction func edit(_ sender: Any) {
tableView.isEditing = !tableView.isEditing
switch tableView.isEditing {
case true:
editButton.title = "Done"
case false:
editButton.title = "Edit"
}
}
// when "New Item" button is tapped, it will segue to
// NewItemViewController... set the callback closure here
// prepare for segue is called when you have created a segue to another view controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// error checking is always a good idea
// this properly unwraps the destination controller and confirms it's
// an instance of NewItemViewController
if let vc = segue.destination as? NewItemViewController {
// callback is a property we added to NewItemViewController
// we declared it to return a String
vc.callback = { item in
self.tableViewData.append(item)
self.tableView.reloadData()
self.navigationController?.popViewController(animated: true)
}
}
}
}
When you tap the "Add Item" button, we're assuming you have that connected to segue to the "New Item" view controller. By implementing:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
we will get a reference to the "New Item" view controller that is about to appear, and we'll assign it a "callback closure".
When we type some text and tap the "Add" button in the next controller, it will "call back" to the first controller, passing the newly typed text. That is where we'll update the data array, reload the table, and pop back on the navigation stack.
Unexpectedly found nil while unwrapping an optional value when loading tableView
I let it sit for a few days and I came back to realize a very dumb mistake I made. I working with around 15 view controllers right now and realized I had a duplicate of the one I posted above with the same name. I now understand why you say working with storyboards is very sticky. Though, I did not need it, I appreciate the help and I can say I learned a few things.
UITABLEVIEW Fatal error: Unexpectedly found nil while unwrapping an Optional value: when Core Data object is updated
Never retrieve cells from the table view force unwrapped. Don't do that. Be aware that a cell can be not on screen at the moment.
The most reliable way is to call only the methods to insert/delete/reload rows in the delegate method
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert: tableView.insertRows(at: [newIndexPath!], with: .automatic)
case .delete: tableView.deleteRows(at: [indexPath!], with: .fade)
case .update: tableView.reloadRows(at: [indexPath!], with: .none)
case .move:
tableView.deleteRows(at: [indexPath!], with: .automatic)
tableView.insertRows(at: [newIndexPath!], with: .fade)
}
}
and handle configure somewhere else for example inside cellForRowAt
Error:Unexpectedly found nil while unwrapping an Optional value. Occurs when I assign a value to TextView which is part of UITableViewCell
Two issues:
- If the cell is designed as prototype cell in Interface Builder and you don't use an extra XIB you must not register the cell.
- If
queryPosts()
is supposed to populate the data source array you have to setdelegate
anddatasource
before calling the method.
The best way is to connect both in Interface Builder and delete the two lines.
override func viewDidLoad()
{
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
queryPosts()
}
How to fix IBOutlet unexpectedly found nil error when binding data with RxSwift?
You have registered the cell class against your reuse identifier. This just instantiates your cell instances without any reference to your XIB file, and so the outlets are not connected.
You need to register the XIB file against the reuse identifier.
private func setupUI() { // Called in viewDidLoad()
resultsTv.register(UINib(nibName: "yourNib", bundle: nil), forCellReuseIdentifier: ResultCell.IDENTIFIER)
}
Label.text Error! - Unexpectedly found nil while implicitly unwrapping an Optional value
The problem is the protocol. You set delegate
to an instance which is not the instance in the storyboard.
But with the given code you don't need the protocol at all.
Delete
protocol artistViewModelDelegate {
func loadArtistViewModel(data: ArtistViewModel)
}
...
var delegate: artistViewModelDelegate?
...
self.delegate = ArtistViewController()
and the protocol conformance, then replace
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
artistViewModel = ArtistViewModel(artist: data[indexPath.row])
let artistViewController = storyboard?.instantiateViewController(withIdentifier: "ArtistViewController") as! ArtistViewController
delegate?.loadArtistViewModel(data: artistViewModel!)
self.navigationController?.pushViewController(artistViewController, animated: true)
}
with
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let artistViewController = storyboard?.instantiateViewController(withIdentifier: "ArtistViewController") as! ArtistViewController
artistViewController.artistViewModel = ArtistViewModel(artist: data[indexPath.row])
self.navigationController?.pushViewController(artistViewController, animated: true)
}
And in ArtistViewController
you have to use a temporary variable for the model because the outlets are not connected (yet) right after instantiation.
Replace the code in the question with
import UIKit
class ArtistViewController: UIViewController, artistViewModelDelegate {
@IBOutlet weak var artwork: UIImageView!
@IBOutlet weak var artistName: UILabel!
@IBOutlet weak var albumName: UILabel!
var artistViewModel : ArtistViewModel!
override func viewDidLoad() {
super.viewDidLoad()
artistName.text = artistViewModel.artistName
}
}
Related Topics
Nspredicate for Array of Dictionaries
Nearby Bluetooth Devices Using Swift 3.0
Uibarbuttonitem Custom View in Uinavigationbar
Apple Watch - Only Getting Data If App on Phone Is Active
Firebase Dynamic Link Always Goes to App Store Url Even If the App Is Installed
Uitapgesturerecognizer on Uiimageview Within Uitablevlewcell Not Getting Called
Constraints for Centering One Button When the Other Is Hidden
Hide Red Recording Status Bar in iOS App When Not Recording
Multiple Unusernotifications Not Firing
How to Expose Existing Property on Obj-C Class Using an Extension Protocol in Swift
iOS Permission Alerts - Removing or Suppressing
Does iPhone Support Hardware-Accelerated Aes Encryption
Uploads Using Backgroundsessionconfiguration and Nsurlsessionuploadtask Cause App to Crash
Static VS Class as Class Variable/Method (Swift)
Uipickerview as Inputview of Uitextfield
iOS - Linking Framework Storyboard to Viewcontroller for Use in Main Project