1

I have question about expandable table view by header. I made it for section zero and its working correctly but when I try to make it same thing for section one too it gives error which is

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).

If I didn't trigger second header function, first one still working. When I clicked second header ( which is section one) it gives that error.

Here my header view code:

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if section == 0 {
        let button = UIButton(type: .system)
        button.setTitle("Kapat", for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.backgroundColor = .lightGray
        button.titleLabel!.font = UIFont.boldSystemFont(ofSize: 14)
        button.addTarget(self, action: #selector(handleExpandCloseForAlim(sender:)), for: .touchUpInside)
        return button
    }
    if section == 1 {
        let button2 = UIButton(type: .system)
        button2.setTitle("Kapat", for: .normal)
        button2.setTitleColor(.black, for: .normal)
        button2.backgroundColor = .lightGray
        button2.titleLabel!.font = UIFont.boldSystemFont(ofSize: 14)
        button2.addTarget(self, action: #selector(handleExpandCloseForTeslim(sender:)), for: .touchUpInside)
        return button2
    }
    else{
        return nil
    }
}

Here my action functions:

    @objc func handleExpandCloseForAlim(sender: UIButton) {

        var indexPaths = [IndexPath]()
        for row in self.userAdressDict.indices{

            let indexPath = IndexPath(row: row, section: 0)
            indexPaths.append(indexPath)
        }
        let indexPath = IndexPath(row: (sender.tag), section: 0)
        let adresso = self.userAdressDict[indexPath.row]
        let isExp = adresso.isExpanded
        adresso.isExpanded = !isExp!
        if isExp! {
            tableView.deleteRows(at: indexPaths, with: .fade)
        }else {
            tableView.insertRows(at: indexPaths, with: .fade)
        }
        print(adresso.isExpanded!, adresso.userMahalle!)

}
@objc func handleExpandCloseForTeslim(sender: UIButton) {
    var indexPathsForTeslim = [IndexPath]()
    for row in self.userAdressDictForTeslim.indices{

        let indexPath = IndexPath(row: row, section: 1)
        indexPathsForTeslim.append(indexPath)
    }
    let indexPath = IndexPath(row: (sender.tag), section: 1)
    let adresso = self.userAdressDictForTeslim[indexPath.row]
    let isExp = adresso.isExpanded
    adresso.isExpanded = !isExp!
    if isExp! {
        tableView.deleteRows(at: indexPathsForTeslim, with: .fade)
    }else {
        tableView.insertRows(at: indexPathsForTeslim, with: .fade)
    }
    print(adresso.isExpanded!, adresso.userMahalle!)
}

And here my numberOfRowsInSection part:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0 {
        guard let element = self.userAdressDict.first as? adresStruct else { return 0 }

            if element.isExpanded {
                return self.userAdressDict.count
            }
            else {
               return 0
            }
        }
        if section == 1 {
              guard let teslim = self.userAdressDictForTeslim.last as? adresStruct else { return 0 }

              if teslim.isExpanded {
                  return self.userAdressDictForTeslim.count
              }
              else {
                 return 0
              }
        }

        return 1
}

I can't find any solution. I assume sender thing working wrongly but it may be another problem. I hope I asked clearly.Please help me.

swifty2
  • 101
  • 9
  • Looks like you are editing the table rows but not your datamodel and they are out of sync. See also here: https://stackoverflow.com/questions/21870680/invalid-update-invalid-number-of-rows-in-section-0 – koen Oct 17 '19 at 11:39
  • I need to delete my data from my model as I understand is this right? Commit editingStyle can help me? – swifty2 Oct 17 '19 at 11:52
  • I don't know, but based on the answer in the link, that looks like it. – koen Oct 17 '19 at 12:02
  • I tried that but it didn't solve. I edited my question it might be more clear now. – swifty2 Oct 17 '19 at 12:37
  • Again, you need to indicate exactly at which line you get the error, otherwise it is a guessing game. Did you try breakpoints and step through your code and inspect the values of your data models? – koen Oct 17 '19 at 12:43
  • When I make section: 1 in here `let indexPath = IndexPath(row: row, section: 1)` it will crash. When I make it zero its working for section zero by section one's header button. – swifty2 Oct 17 '19 at 12:48
  • Merhaba @swifty2, I will add an answer but not way like you are doing. I hope it helps for you. – eemrah Oct 17 '19 at 12:53
  • @elia I will definitely try. – swifty2 Oct 17 '19 at 12:57
  • may be case is section 1 is not expended and but `adresso.isExpanded` is already set true. – golu_kumar Oct 17 '19 at 12:59
  • @Koen I already said ? – swifty2 Oct 17 '19 at 13:10
  • @swifty2 is it worked? – eemrah Oct 17 '19 at 13:13

1 Answers1

1

I am not deep dive in your code but I copy-paste into an Xcode project to look into. So there is basic way to solve your problem, I hope it helps to you.

I assume your class is like that.

class Adres{
        var title: String = ""
        var isExpanded: Bool = true

        init(title: String, isExpanded: Bool){
            self.title = title
            self.isExpanded = isExpanded
        }
    }

And in there mainly 2 different variable for adresDict & adresDictForTeslim.

So I keep an lock array to doing logic stuff of expandable.

var keys: [Int] = [1,1]

<1> Show
<0> Hide

Now, the arrays elements are showing into UITableView, because its expanded.

There's mock data.

var userAdressDict = [Adres(title: "First Adres", isExpanded: true) ,Adres(title: "Second Adres", isExpanded: true)]
    var userAdressDictForTeslim = [Adres(title: "First Teslim", isExpanded: true),Adres(title: "Second Teslim", isExpanded: true)]

viewForHeaderInSection is same as well.

And for numberOfRowsInSection check array for key that if its expanded or not.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            if self.keys[0] == 1 {
                return userAdressDict.count
            }else{
                return 0
            }
        }else{
            if self.keys[1] == 1 {
                return userAdressDictForTeslim.count
            }else{
                return 0
            }
        }
    }

Then check these keys in handler functions.

 @objc func handleExpandCloseForAlim(sender: UIButton) {

    if keys[0] == 0 {
        keys[0] = 1
    }else{
        keys[0] = 0
    }

    DispatchQueue.main.async {
        self.tableView.reloadData()
    }
}

If first array elements in table view is expanded close it, or not expand it.

Then in another function.

@objc func handleExpandCloseForTeslim(sender: UIButton) {

        if keys[1] == 0 {
            keys[1] = 1
        }else{
            keys[1] = 0
        }
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }

So far so good. It's working on my simulator.

Then there's more efficient way to handle keys of expanded.

Make your UIButton's of the sectionHeader as public variable in your ViewController and control it if it's title is "Kapat" and clicked then it must be "Aç" or if its "Aç" and touched it must be "Kapat".

eemrah
  • 1,603
  • 3
  • 19
  • 37
  • Thank you so much I will try it now. But my class a little more complicated. I will edited and add my class too. – swifty2 Oct 17 '19 at 13:13
  • @swifty2 no matter. just use isExpanded property like I describe. – eemrah Oct 17 '19 at 13:13
  • I think you don't have to do this. Just trick for you, don't remove any data from your array's. And assume there are 2 exact section for the UITableView. – eemrah Oct 17 '19 at 13:40
  • but section 2 is still closing section 1. I really don't understand why. Is this because of the sender? – swifty2 Oct 17 '19 at 13:43
  • maybe you can write it wrong. first handler must be worked with `keys[0]`and the other is with `keys[1]` – eemrah Oct 17 '19 at 13:44
  • I have to give that sender to identity but I can't find any sample for that. Anyway I am really happy for your help thank you so much... – swifty2 Oct 17 '19 at 13:49
  • 1
    @swifty2 I recommend don't use insertRow or deleteRow method, because when you use these methods the number of rows must be equal in before and after. Use count of the array and 0 for open & closed situations. And for senders like in my answer 2 different button actions are connected with seperated button's. In your code there's nothing wrong with button – eemrah Oct 17 '19 at 13:51
  • @swifty2: even though this may have solved your problem, I highly recommend that you read the answers in the "this question already has an answer" box at the top of this page. I explains very well how to make your data model when you are dealing with dynamic sections. Good luck. – koen Oct 17 '19 at 14:23
  • @Koen I will look it now. Thanks. – swifty2 Oct 17 '19 at 15:10
  • @elia its works you are the best! – swifty2 Oct 17 '19 at 15:16
  • glad to help :) – eemrah Oct 17 '19 at 15:47