1

I have a Stack in my ViewController and I want to load a nib file(which contain a tableview) and add it to the stack. when I add it in viewDidLoad, there is no problem but when I put it in viewDidAppear app crash and got this error:

fatal error: unexpectedly found nil while unwrapping an Optional value

There are some UITableViewCell which I return them in cellForRowAt function based on row. It seems nib files are nil when they load and added in viewDidAppear!

Here is my code:

class MyOrdersViewController: UIViewController {

@IBOutlet weak var stack: UIStackView!
override func viewDidLoad() {
    super.viewDidLoad()
    //setCards()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    setCards()
}


func setCards(){
        let orderCard = NibLoader.loadViewFromNib(name: "MyOrdersView", selfInstance: self, nibType: MyOrdersView.self) as! MyOrdersView   
        stack.addArrangedSubview(orderCard)
}
}


class MyOrdersView: UIView,UITableViewDelegate,UITableViewDataSource {

@IBOutlet weak var tableView: UITableView!

@IBOutlet weak var seprator: UITableViewCell!

@IBOutlet weak var date: UILabel!
@IBOutlet weak var firstCell: UITableViewCell!
@IBOutlet weak var code: UILabel!

@IBOutlet weak var secondCell: UITableViewCell!
@IBOutlet weak var price: UILabel!

@IBOutlet weak var thirdCell: UITableViewCell!
@IBOutlet weak var orderStep: UILabel!

@IBOutlet weak var payModel: UILabel!
@IBOutlet weak var cancelBtn: UIButton!
@IBOutlet weak var fourthCell: UITableViewCell!

override func awakeFromNib() {
    tableView.delegate = self
    tableView.dataSource = self
    UIFunctions.setBordersStyle(view: cancelBtn, radius: 5, width: 1, color: UIColor.red)
}

func setValue(order:Order){
    self.date.text = order.order_date
    self.code.text = String(describing: order.order_code ?? 0)
}

// MARK: - Table view data source

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 5
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    var cell=UITableViewCell()

    switch indexPath.row {
    case 0:
        cell = seprator
    case 1:
        cell = firstCell
        cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
    case 2:
        cell = secondCell
        cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
    case 3:
        cell = thirdCell
        cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
    case 4:
        cell = fourthCell
    default:
        break
    }

    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

    var height = 0
    switch indexPath.row {
    case 0:
        height = 25
    case 4:
        height = 70
    default:
        height = 50
    }

    return CGFloat(height)
}
}
Hamed Ghadirian
  • 6,159
  • 7
  • 48
  • 67

1 Answers1

2

The reason seems that since viewDidLoad is the first method to be called in the view life cycle, adding nib reference there makes sure that when the views are drawn(your tables), they are available to locate in cellForRow.

But if you put the same code in viewDidAppear, the views are already loaded by that time, and your table view is not referenced yet referenced from Nib. Hence the nil error.

This link discusses the various view lifecycle methods and their calling order in detail.

Umar Farooque
  • 2,049
  • 21
  • 32
  • So how could I add view (which contain tableview) to the stack at run time? – Hamed Ghadirian Aug 12 '17 at 13:04
  • yeah, I send request to the server and it returns a list of items ( and array of arrays) – Hamed Ghadirian Aug 12 '17 at 13:10
  • I dont understand where server calls are made but if you just want to update the table views after the response is received from server, it should work.. you would have to just update your array which would initially contain 0 elements and display empty table and afterwards will display data response from server.. just keep the NibLoader.loadViewFromNib in viewDidLoad rest should be handled – Umar Farooque Aug 12 '17 at 13:16
  • Its just a sample code that I put there. I just wanted to show that I could not call setCards function anywhere except in viewDidLoad, I don't know how many times should I call setCards.It determines after the response from server (request called in viewDidLoad but after receiving the response I can not call setCards function) – Hamed Ghadirian Aug 12 '17 at 13:23
  • Ideally it should be called just once, because it just sets the view for you. If you want to update the data inside that view (in your case the tableview) you should update the array used inside the table view and reload table. – Umar Farooque Aug 12 '17 at 13:29
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/151785/discussion-between-hamed-gh-and-umar-farooque). – Hamed Ghadirian Aug 12 '17 at 13:33