Reputation: 220
A little context - I have one ViewController called SelectedListItemsViewController that has a TableView populated by an array of Realm Model Objects called selectedListItems
. There's an Add bar button item that navigates to another ViewController called AllListItemsViewController that has a TableView populated by an array of Realm Model Objects called allListItems
, with each cell containing a UISwitch.
Both of the aforementioned arrays are based off the same class, which has a boolean property called isSelected
. In my code, I currently have it set up so that when I toggle the UISwitch in the cell in the AllListItemsViewController, if it turns 'on' the isSelected
property at that indexPath.row
of allListItems
is changed to true
and the object is appended to the selectedListItems
array. This part seems to work fine.
Toggling the switch to 'off' causes the isSelected
property of that indexPath.row
of allListItems
to change to false
and the object is removed at its index from selectedListItems
. This works in most cases, but there are times where toggling the UISwitch of cells 'off' in the wrong order (if they were turned 'on' at index 0, then 1, then 2, and then I try to turn index 1 'off') then it crashes the simulation, presumably due to the index being out of range.
I'm very amateur when it comes to programming, so I'm sure the following code is sloppy and I doubt I'm achieving my objective in the best/most efficient way.
// The following arrays are for use with UISegmentedControl (other three removed for brevity)
// This is an array of 'Appearance' list items created from allListItems
let appearanceArray = allListItems.filter{
$0.category.rangeOfString("Appearance") != nil
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath:
NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! AllListItemsTableViewCell
// This is a string value for the cell at indexPath.row
var listItemInCell = ""
// This is an array of all listItems in allListItems, and used with indexOf to check boolean status of isSelected inside of allListItems array
let arrayAll = allListItems.map{($0.listItem)}
// This is an array of all listItems in selectedListItems, and used to track remove indexes
let arraySelected = selectedListItems.map{($0.listItem)}
switch(segmentedControl.selectedSegmentIndex)
{
case 0: // Case 0 of 4, the others removed for brevity of this question
listItemInCell = appearanceArray[indexPath.row].listItem
// Index of listItemInCell inside of the array of allListItems' listItems
let indexOf = arrayAll.indexOf(listItemInCell)!
cell.listItemLabel.text = listItemInCell
// Tracks UISwitch activity
cell.callback = { (tableViewCell, switchState) in
if self.tableView.indexPathForCell(tableViewCell) != nil {
// do something with index path and switch state
if switchState == true {
allListItems[indexOf].isSelected = true
selectedListItems.append(self.appearanceArray[indexPath.row])
} else {
allListItems[indexOf].isSelected = false
let indexInSelected = arraySelected.indexOf(listItemInCell)!
selectedListItems.removeAtIndex(indexInSelected)
}
}
}
if appearanceArray[indexPath.row].isSelected {
cell.toggleIsSelected.on = true
} else {
cell.toggleIsSelected.on = false
}
break
Is there a better way of going about this that doesn't have edge cases that cause runtime errors? One thought I had was that recording the index of selectedListItems
might not be the best route since it's a global variable and computed lazily, so it isn't always up to date. Another thought is that something gets lost in translation when I'm creating arrays of the object's property to track an index, instead of being able to find the index of a given spot in the array of objects itself.
Upvotes: 0
Views: 166
Reputation: 220
After flailing around at it for the last 3 hours, I figured it out. In my else case of switchState
, instead of using
let indexInSelected = arraySelected.indexOf(listItemInCell)!
selectedListItems.removeAtIndex(indexInSelected)
I instead used
let objectToRemove = self.appearanceArray[indexPath.row]
for object in selectedListItems {
if object == objectToRemove {
selectedListItems.removeAtIndex(selectedListItems.indexOf(objectToRemove)!)
}
}
Which seems to have completely fixed my index-out-of-range issue I was having with some delete cases. It also looks like I can get rid of a decent amount of the unnecessary code I have that was supporting the original two lines.
Upvotes: 0