UITableView Crashes on Segue to View Controller - ios

Cause of Crash
Click the image above for a brief view of my Segue. My app is a workout tracker. I have a class that makes the workout object with properties such as workout name, description, etc. I have another object that creates the workoutlist, so just an array of Workout objects.
I have a UITableView and a button above it that lets the user create a new workout and adds it to the workoutList array.
The crash happens whenever I click this "create new workout" which segues to a new view controller. I get this error
Crash Error
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var setStepper: UILabel!
#IBOutlet weak var repStepper: UILabel!
#IBOutlet weak var workoutName: UITextField!
#IBOutlet weak var workoutDescription: UITextField!
#IBOutlet weak var tableView: UITableView!
var workoutList = WorkoutList().listOfWorkouts
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func stepperCounter(_ sender: UIStepper) {
if sender.tag == 1 {
setStepper.text = "\(Int(sender.value))"
}
else if sender.tag == 2 {
repStepper.text = "\(Int(sender.value))"
}
}
#IBAction func addToWorkout(_ sender: Any) {
//I know this is terrible fixing later. Just for Testing right now
let newWorkout : Workout = Workout(Name: workoutName.text!, Description: workoutDescription.text!, Sets: Int(setStepper.text!)!, Reps: Int(repStepper.text!)!)
workoutList.append(newWorkout)
print(workoutList.count)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return workoutList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Hello"
return cell
}
}

it looks like you are using the same ViewController for both Views in your storyboard.
Which means, when you push to the "AddNewWorkoutController" the viewDidLoad expects a tableView - which is not there, because the storyboard didn't build any for this view.
You should create 2 VCS. One for the OverView with the "add new button" and the tableview and another one for actually creating it.
here is a full solution:
create 2 new swift files:
OverViewViewController.swift & NewWorkoutViewController.swift
I just separated your code into 2 VC's:
import UIKit
class OverViewViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var workoutList = WorkoutList().listOfWorkouts
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return workoutList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Hello"
return cell
}
}
and
import UIKit
class NewWorkoutViewController: UIViewController {
#IBOutlet weak var setStepper: UILabel!
#IBOutlet weak var repStepper: UILabel!
#IBOutlet weak var workoutName: UITextField!
#IBOutlet weak var workoutDescription: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func stepperCounter(_ sender: UIStepper) {
if sender.tag == 1 {
setStepper.text = "\(Int(sender.value))"
}
else if sender.tag == 2 {
repStepper.text = "\(Int(sender.value))"
}
}
#IBAction func addToWorkout(_ sender: Any) {
//I know this is terrible fixing later. Just for Testing right now
let newWorkout : Workout = Workout(Name: workoutName.text!, Description: workoutDescription.text!, Sets: Int(setStepper.text!)!, Reps: Int(repStepper.text!)!)
workoutList.append(newWorkout)
print(workoutList.count)
}
}
Now go into the Storyboard, select the controllers and assign the right classes:
After assigning go and connect your tableView to the tableView in the OverView and the 2 actions in your NewWorkout.
This will work.

I'd guess that tableView outlet isn't wired up in your storyboard - and that property is an implicitly unwrapped optional. You're promising that it won't be nil.

Related

tableview doesn't show anything?

I made sure that my cell identifier was correct I'm not too sure what the problem is. I've been rereading the code on this viewController and I'm not sure if I'm missing something or if there's a specific reason why my tableview isn't loading.
import UIKit
import JGProgressHUD
class BasketViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = footerView
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//MARK: TO DO CHECK IF USER IS LOGGED IN
loadBasketFromFirestore()
}
//MARK: VARS
var basket : basket?
var allItems : [Item] = []
var purchaseItemID : [String] = [] //holds id of items you want to purchase
var hud = JGProgressHUD(style: .dark)
//MARK: IBOUTLETS
#IBOutlet weak var totalPriceLabel: UILabel!
#IBOutlet weak var totalItemsInBasket: UILabel!
#IBOutlet weak var checkOutButton: UIButton!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var footerView: UIView!
//MARK: IBACTIONS
#IBAction func checkOutButtonTapped(_ sender: Any) {}
//something is wrong with
//MARK: DOWNLOAD BASKET
private func loadBasketFromFirestore(){
//MARK: CHANGE 1234 TO A USER ID STRING
downloadBasketFromFirestore("1234") { (basket) in
self.basket = basket
self.getBasketItems()
}
}
private func getBasketItems(){
if (basket != nil) {
print("getting items")
downloadItems(_withIDS: basket!.itemID) { (allItems) in
self.allItems = allItems
self.tableView.reloadData()
}
} else { print("basket is nil")}
}
}
extension BasketViewController : UITableViewDataSource , UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "basketCell", for: indexPath) as! ITEMTableViewCell
cell.generateCellForITEMS(item: allItems[indexPath.row])
return cell
}
}

How to get #IBAction func data into TableView?

I'm writing a tableview for my search results in iOS.
This is my ViewController:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var resultArray = NSMutableArray()
#IBOutlet weak var scoreTableView: UITableView!
#IBOutlet weak var inputText: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
scoreTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
XXXXXXX
return cell
}
And this is my search and #IBAction func.
func search() -> NSMutableArray{
XXXXXXXXX
return array
}
#IBAction func btnSearch(_ sender: Any) {
resultArray = search()
}
However, after building, my table view is blank. In debugDescription(), I can see that func search() works well and have printed search log.
The resultArray in tableview is not the one in #IBAction. It is empty.
You have to reload data again after changing resultArray.
#IBAction func btnSearch(_ sender: Any) {
resultArray = search()
scoreTableView.reloadData()
}
Update: I just forgot to assign DataSource and Delegate to tableView. I built tableview manually from storyboard.
And I misunderstood that there's need to assign DataSource and Delegate, if I did it in storyboard.
override func viewDidLoad() {
super.viewDidLoad()
scoreTableView.dataSource = self
scoreTableView.delegate = self

Xcode UIButton to UITableView not connecting

I am designing a project where I want it to go to a table view when a button is clicked.
Here is a pic of the storyboard:Storyboard
Here is the code for the view with the button:
import UIKit
import os.log
class MealViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//MARK: Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var photoImageView: UIImageView!
#IBOutlet weak var ratingControl: RatingControl!
#IBOutlet weak var caloriesLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBAction func addToCart(_ sender: UIButton) {
}
and here is the table view code:
import UIKit
class CartTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
When I run it how it is, it opens a blank table. When I change the numberOfRowsInSection, it gives a sigabrt error. How can I get it to just open the view regularly?
The function numberOfRowsInSection define the count of rows in the given section. If you define 0 the table must be empty. If you define something else the table view asks for a concrete cell for each row by calling:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
Depending on your code thats the first place to look for the crash reason. Your code snipped doesn't show it.

Segueing to a different tab in a UITabController

I am trying to segue data from my "create a party" form into my second "Find Parties" tab.
Here is a screen shot of my main story board:
my code for the create a party controller:
import UIKit
struct party {
var name: String
var location: String
var description: String
}
class FirstViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var locationField: UITextField!
#IBOutlet weak var descriptionField: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var newParty = party(name: "", location: "", description: "")
#IBAction func create(_ sender: AnyObject) {
newParty = party(name: nameField.text!, location: locationField.text!, description: descriptionField.text!)
nameField.text = ""
locationField.text = ""
descriptionField.text = ""
performSegue(withIdentifier: "toPartyList", sender: newParty)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationViewController : SecondViewController = segue.destination as! SecondViewController
destinationViewController.parties.append(newParty)
}
}
Code for the find parties tab:
import UIKit
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var partyTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
partyTable.delegate = self
partyTable.dataSource = self
// updates the table of users everytime submit is clicked
DispatchQueue.main.async{
self.partyTable.reloadData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var parties = [party]()
// creates the number of cells in the table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parties.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Make table cells the show the user name
let cell = UITableViewCell()
cell.textLabel?.text = parties[indexPath.row].name
return cell
}
// Allows the user to swipe and delete people from the table and also the users array
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// delete the person in users array
parties.remove(at: indexPath.row)
// delete the cell from the table
partyTable.deleteRows(at: [indexPath], with: .fade)
}
}
}
currently my segue just takes me directly to the "Find Parties" view controller with no way back, and not to the tab. what do I need to change in my segue to do this?
Rather than use a segue in this case, just switch tabs programatically:
#IBAction func create(_ sender: AnyObject) {
newParty = party(name: nameField.text!, location: locationField.text!, description: descriptionField.text!)
nameField.text = ""
locationField.text = ""
descriptionField.text = ""
tabBarController?.selectedIndex = 1 // 2nd tab
}
To pass information along, you can do something like this:
let navVC = tabBarController.viewControllers[1] as! UINavigationController
let rootVC = navVC.viewControllers[0] as! SomeViewController
rootVC.someData = myData

UITableView doesn't fill custom cells inside of UITabBarController

I have UITabBarController and on one of the tabs I have UIViewController with UITableView inside.
I had created custom cell class.
If I fill tableView custom cells without UITabBarController (I put entry point to UIViewController) everything works fine, but if I use UITabBarController firstly, my cells are not populated with any data when I reach UITableView tab.
Where could be a bug here?
import UIKit
class blaViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak 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 3
}
func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! blaTableViewCell
cell.myLabel.text = "123"
return cell
}
}
import UIKit
class blaTableViewCell: UITableViewCell {
#IBOutlet weak var myLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Try tick install checkbox for all the constraints, not only wh wr. It worked for me. It is also described here: https://stackoverflow.com/a/32052154/2064500
#IBOutlet weak var myLabel: UILabel!
Try to do strong variable
#IBOutlet var myLabel: UILabel!

Resources