4

I need to call a function after the UITableView has been loaded completely. I know that in most cases not every row is displayed when you load the view for the first time, but in my case, it does as I only have 8 rows in total.

The annoying part is that the called function needs to access some of the tableView data, therefore, I cannot call it before the table has been loaded completely otherwise I'll get a bunch of errors.

Calling my function in the viewDidAppear hurts the user Experience as this function changes the UI. Putting it in the viewWillAppear screws up the execution (and I have no idea why) and putting it in the viewDidLayoutSubviews works really well but as it's getting called every time the layout changes I'm afraid of some bugs that could occur while it reloads the tableView.

I've found very little help about this topic. Tried few things I found here but it didn't work unfortunately as it seems a little bit outdated. The possible duplicate post's solution doesn't work and I tried it before posting here.

Any help is appreciated! Thanks.

Edit: I'm populating my tableView with some data and I have no problems with that. I got 2 sections and in each 4 rows. By default the user only sees 5 rows (4 in the first section, and only one in the second the rest is hidden). When the user clicks on the first row of the first section it displays the first row of the second section. When he clicks on the second row of the first section it displays two rows of the second section, and so on. If the user then clicks on the first row of the first section again, only one cell in the second section is displayed. He can then save his choice.

At the same time, the system changes the color of the selected row in the first section so the users know what to do.

Part of my issue here is that I want to update the Model in my database. If the users want to modify the record then I need to associate the value stored in my database with the ViewController. So for example, if he picked up the option 2 back then, I need to make sure the second row in the first section has a different color, and that two rows in the second sections are displayed when he tries to access the view.

Here's some code :

    func setNonSelectedCellColor(indexPath: NSIndexPath) {
    let currentCell = tableView.cellForRowAtIndexPath(indexPath)
    currentCell?.textLabel?.textColor = UIColor.tintColor()

    for var nbr = 0; nbr <= 3; nbr++ {
        let aCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: nbr, inSection: 0))
        let aCellIndexPath = tableView.indexPathForCell(aCell!)
        if aCellIndexPath?.row != indexPath.row {
            aCell?.textLabel?.textColor = UIColor.blackColor()
        }
    }
}

func hideAndDisplayPriseCell(numberToDisplay: Int, hideStartIndex: Int) {
    for var x = 1; x < numberToDisplay; x++ {
        let priseCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: x, inSection: 1))
        priseCell?.hidden = false
    }
    if hideStartIndex != 0 {
        for var y = hideStartIndex; y <= 3; y++ {
            let yCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: y, inSection: 1))
            yCell?.hidden = true
        }
    }
}

These two functions are getting called every time the user touches a row :

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    let path = (indexPath.section, indexPath.row)
    switch path {
    case(0,0):
        setNonSelectedCellColor(indexPath)
        hideAndDisplayPriseCell(1, hideStartIndex: 1)
        data["frequencyType"] = Medecine.Frequency.OneTime.rawValue
    case(0,1):
        setNonSelectedCellColor(indexPath)
        hideAndDisplayPriseCell(2, hideStartIndex: 2)
        data["frequencyType"] = Medecine.Frequency.TwoTime.rawValue
    case(0,2):
        setNonSelectedCellColor(indexPath)
        hideAndDisplayPriseCell(3, hideStartIndex: 3)
        data["frequencyType"] = Medecine.Frequency.ThreeTime.rawValue
    case(0,3):
        setNonSelectedCellColor(indexPath)
        hideAndDisplayPriseCell(4, hideStartIndex: 0)
        data["frequencyType"] = Medecine.Frequency.FourTime.rawValue

    default:break
    }

}

I store the values in a dictionary so I can tackle validation when he saves.

I'd like the first two functions to be called right after my tableView has finished loading. For example, I can't ask the data source to show/hide 1 or more rows when I initialize the first row because those are not created yet.

As I said this works almost as intended if those functions are called in the viewDidAppear because it doesn't select the row immediately nor does it show the appropriate number of rows in the second sections as soon as possible. I have to wait for 1-2s before it does.

Nikul Maniya
  • 247
  • 2
  • 14
Croisciento
  • 149
  • 1
  • 12
  • Can you provide a bit more information what the errors are? Also, perhaps a bit of relevant code? – Shen Mar 03 '16 at 16:24
  • Can't see the reason behind doing so. You should already know all data needed when initializing the table cells. – zc246 Mar 03 '16 at 16:41
  • This is not a duplicate. I tried the above and this isn't working well for me. – Croisciento Mar 03 '16 at 16:42
  • To go a little further in the duplicate : I've tried this method and it simply isn't suited to what I wanna do. If I call one of my functions I get a `fatal error: unexpectedly found nil while unwrapping an Optional value` because when calling anything related to the tableView returns nil. For example `let aCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: nbr, inSection: 0))` returns nil even thought it has been created already and I have no idea why it's nil. – Croisciento Mar 03 '16 at 17:27
  • You shouldn't need to know when the table has been displayed, it is the user's interaction with the table rows that should cause you to update the table display. You update your data model accordingly and call table update functions such as `reloadRowsAtIndexPaths` or `reloadSections`. The you handle the formatting of the cell in `cellForRowAtIndexPath`. Don't loop through cells and update them directly. Don't set the hidden property; return appropriate values for `numberOfRowsInSection` – Paulw11 Mar 03 '16 at 19:52
  • @Paulw11 Just wanted to say thanks you. I totally reworked my code according to what you said and it works perfectly now. It's actually a lot easier and I have no idea why I didn't thought of this approach back then. – Croisciento Mar 10 '16 at 12:54

1 Answers1

0

If you have the data already that is used to populate the tableView then can't you use that data itself in the function? I am presuming that the data is in the form of an array of objects which you are displaying in the table view. So you already have access to that data and could use it in the function.

But if that's not the case then and if your table view has only 8 rows then you can try implementing this function and inside that check the indexPath.row == 7 (8th row which is the last one).

tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)

Since all your rows are visible in one screen itself without scrolling you could use this function to determine that all the cells have been loaded and then call your function.

Pradeep K
  • 3,671
  • 1
  • 11
  • 15
  • It's not getting called for me. And according to the documentation this delegate is to detect when a row has been removed from the tableView. – Croisciento Mar 03 '16 at 17:29
  • are you using only custom data source, didenddisplaying is a method from tableview delegate set tableview.delegate to get called it – Ratul Sharker Mar 03 '16 at 18:19