0

I am trying to remove an item from a public static array that is been shown in a tableview. The deletion is occuring in a different viewcontroller and when I try to enter that view controller the app crashes with the error of 'Index out of range'

this is where i delete the Item

func removeItem (info:Dictionary<String, Any>){
    let stringKey = info[KEYS.stringKey] as! String
    for var i in 0 ..< ItemsViewController.itemVideosList.count {

        let current = ItemsViewController.itemVideosList[i]
        let currentStringKey = current[KEYS.stringKey] as! String

        if stringKey == currentStringKey {

            ItemsViewController.itemVideosList.remove(at: i)
            return
        }
    }

I call this method on a button click here:

@IBAction func FavoriteAction(_ sender: Any) {


    if Flag {
        removeFromFavorite(info: songInfo)
        Flag = false
        }
    else {
        ItemsViewController.itemVideosList.insert(songInfo, at: 0)
        favFlag = true
    }
}

I am populating the table view in 'ItemsViewController' viewDidLoad with this method

func loadItems() {
    DispatchQueue.main.async {
        self.itemsTableView.reloadData()
    }
}

thanks

Fabio Berger
  • 1,921
  • 2
  • 24
  • 29
Ittai Oren
  • 542
  • 5
  • 10

1 Answers1

1

You are trying to loop through when deleting. This leads to ItemsViewController.itemVideosList.count being invalid after your deletion.

  1. You can solve your problem simply by adding a break instead of a return

    if stringKey == currentStringKey {
        ItemsViewController.itemVideosList.remove(at: i)
        return
    }
    
  2. More importantly, you should not modify a collection while iterating it. This leads to undesired side effects. It's better to just store the indexToDelete and then delete it outside of loop.

    func removeItem (info:Dictionary<String, Any>){
    let indexToRemove = -1
    let stringKey = info[KEYS.stringKey] as! String
    for var i in 0 ..< ItemsViewController.itemVideosList.count {
    
        let current = ItemsViewController.itemVideosList[i]
        let currentStringKey = current[KEYS.stringKey] as! String
    
        if stringKey == currentStringKey {
            indexToDelete = i            
            break
        }
    }
    
    ItemsViewController.itemVideosList.remove(at: indexToDelete)
    }
    

Note:

You could make your iteration cleaner using higher-order functions like so:

var list = ["a", "b", "c"]

let index = list.index { (str) -> Bool in
    if str == "b" {
        return true
    }
    return false
}
jarora
  • 5,384
  • 2
  • 34
  • 46
  • I think the problem is when i reload the tableview. (altho your answer is important for me also). The prints that i added show that the item is deleted but when i try to re-enter the view controller it crashes. – Ittai Oren Aug 08 '17 at 08:41
  • @IttaiOren after deletion are you on same controller or performing some segue? – Tushar Sharma Aug 08 '17 at 08:45
  • @Tushar Sharma I am on the same controller. the deletion deletes an item in a static list and when user chooses to go to that controller the list will populate the tableview – Ittai Oren Aug 08 '17 at 08:52
  • You can post a notification that the other viewController listens to. And then reloads the data – jarora Aug 08 '17 at 09:11
  • can you give me an example for this kind of notification and listener? – Ittai Oren Aug 08 '17 at 09:39
  • I found a good example and it works (https://stackoverflow.com/questions/25921623/how-to-reload-tableview-from-another-view-controller-in-swift). Thanks for the help – Ittai Oren Aug 08 '17 at 09:59
  • Glad I could help :) – jarora Aug 08 '17 at 10:06