3

in the UIViewController's viewDidLoad() there is a method being called for updating a class variable. Once I navigate to another view controller and come back to this one, UITableView's delegate methods are being called first where that class variable is being used. App is crashing because that variable is being constructed in viewDidLoad(). How can this issue be fixed? Thank you.

the class variable in question:

var showHideDict = Dictionary<Int, Bool>()

the viewDidLoad():

override func viewWillAppear() {
    super.viewWillAppear()
    makeAPICall()
}

the API calling method:

func makeAPICall() {
    // create helper object
    let helper = ModelHelper()
    helper.createModels(receivedDict: result! as NSDictionary)

            // store the showHideDict
    for index in 0...(Modelclass.models.count - 1) {
        self.showHideDict[index] = true
    }

    DispatchQueue.main.async {
         self.tableView.reloadData()
    }
}
as diu
  • 1,010
  • 15
  • 31
  • 1
    by posting code not paraphrasing your code in sentences. So far this sounds like it either should work out of the box or a duplicate of https://stackoverflow.com/questions/46521391/xcode-swift-viewdidload – luk2302 Oct 03 '17 at 16:40
  • added code instead of paraphrasing. Thank you for responding. – as diu Oct 03 '17 at 17:03
  • Why are you calling `viewWillAppear()`? Shouldn't that be `super.viewWillAppear()`? – toddg Oct 03 '17 at 17:08
  • changed it. thank you! – as diu Oct 03 '17 at 17:09
  • 1
    construct the variable in init() – scord Oct 03 '17 at 17:12
  • @scord the variable requires API call to be made, the API call requires a spinner to be shown.. thats why I'm not using `init()`. is there a way around? – as diu Oct 03 '17 at 17:20
  • @asdiu I think this is actually an instance variable, not a class var, right? If `showHideDict` is an instance variable why will it not still be around when you return to this screen? Secondly, as a workaround couldn't you just construct this var in `viewWillAppear`? Downside is that it would trigger an unnecessary network transaction. – toddg Oct 03 '17 at 17:29
  • @toddg its actually re visiting this screen the second time instead of revisiting the screen. I put it wrongly. sorry about that. – as diu Oct 03 '17 at 17:30
  • I understand now. I think you'll want to have an empty tableview until your API call is complete then refresh your tableView. – toddg Oct 03 '17 at 17:33
  • @toddg that is exactly my situation. sorry about the confusion. – as diu Oct 03 '17 at 17:34

1 Answers1

3

In your UITableViewDelegate methods I think you'll want to check whether the data in your dictionary is populated as you expect it to be. For instance, this is what I frequently do in my code:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
{
    return tableData?.count ?? 0
}

Which is saying: if tableData is not nil, then return the number of elements in the array. Otherwise return 0

Then in your cellForRowAt method, just conditionally check whether the data in your showHideDict is populated as you expect, if not don't force unwrap. Swift enforces safety with optionals... work with it not against it.

Once your API call is completed, all you need to do is do tableView.reloadData() and the tableview will be constructed with your newly-populated data.

toddg
  • 2,863
  • 2
  • 18
  • 33
  • 1
    this solution worked great for me! earlier I wasn't doing the check whether API data has been received or not. as you rightly indicated in your answer, the key was to check it in `numberOfRowsInSection` and in reload the table data in `cellForRow`. Thank you! – as diu Oct 03 '17 at 18:25