Reputation: 8845
In my app I am storing a list of sets of data in NSUserDefaults. When it needs to be accessed, I create create an array (each key in NSUserDefaults contains and array of data) and use the data. It works great. Yay! Unfortunately, when I display the data in a UITableView, deleting one set of data ( which == one row in the UITableView ) is not working properly. This is how I am going about doing that:
if(buttonIndex == actionSheet.destructiveButtonIndex)
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
int iii = [defaults integerForKey:@"currentMap"];
NSMutableDictionary* dicOne = (NSMutableDictionary*)[[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
for(int lll = iii; lll < [[defaults objectForKey:@"counterKey"] intValue]; lll++)
{
if(lll != [[defaults objectForKey:@"counterKey"] intValue] - 1)
[dicOne setObject:[dicOne objectForKey:[NSString stringWithFormat:@"%i", (iii + 1)]] forKey:[NSString stringWithFormat:@"%i", iii]];
else
[dicOne removeObjectForKey:[NSString stringWithFormat:@"%i", iii]];
}
[defaults setPersistentDomain:dicOne forName:[[NSBundle mainBundle] bundleIdentifier]];
[defaults synchronize];
int counter = [defaults integerForKey:@"counterKey"];
counter--;
[defaults setInteger:counter forKey:@"counterKey"];
[defaults synchronize];
[self performSelector:@selector(done:) withObject:nil afterDelay:.3];
}
The idea behind this code is to start a for loop at the index of the selected row to be deleted ( variable 'iii'). This method moves through the dictionary, moving each index down a level.
Imagine the dictionary containing five sets of data (five keys), labeled 0, 1, 2, 3, and 4. When 2 gets marked for deletion, this code moves through the dictionary, assigning the data contained in key 3 to key 2, the data in key 4 to key 3, then deletes the remaining copy in key three. The counterKey then gets decremented (as this is the number I use to keep track of how many keys exist, so I can tell the UITableView how many cells it needs to create). Or at least that is what I think it should do.
But it doesn't do what I think it should do; when a cell gets marked for deletion, what really happens is that the data for that key shows up as NULL, and the keys do not 'slide' like I think they should.
The done: method dismisses the information view (that contains the delete button and information about the selected row) and returns to the view that holds the UITableView.
Does this concept make sense, and if so, why doesn't it work? Thanks for your time.
***Edit:
Thank you, jrturton, using an NSArray worked, but sometimes deleting it (or trying) crashes with this error:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object' * First throw call stack: (0x14c7052 0x1658d0a 0x146fa78 0x146f9e9 0x14c109f 0xd381 0x8cba1f 0x14c8ec9 0x5105c2 0x51055a 0x5b5b76 0x5b603f 0x5b52fe 0x535a30 0x535c56 0x51c384 0x50faa9 0x24adfa9 0x149b1c5 0x1400022 0x13fe90a 0x13fddb4 0x13fdccb 0x24ac879 0x24ac93e 0x50da9b 0x1ef9 0x1e75)
Which is odd, because there is not a single NSArray used in that class; all of them are mutable.
This is the line of the crash (I am reasonably sure):
NSMutableArray* outerArray = (NSMutableArray*)[defaults objectForKey:@"mapSaveDataKey"];
[outerArray removeObjectAtIndex:iii];
Fix:
Replace:
[defaults objectForKey:@"mapSaveDataKey"];
With:
[defaults mutableArrayValueForKey:@"mapSaveDataKey"];
Upvotes: 1
Views: 1027
Reputation: 119242
What you are doing seems unnecessarily complicated. Why not just have a single array stored in your user defaults, under a key (e.g @"data"
), then remove or add items to that array? This way you don't have to maintain separate counts or anything like that. You can use objectAtIndex:
to get hold of item 4, for example, and when you delete item 2, the items above it will move down a notch anyway.
Update - as Matthew Gillingham points out in the comments, I did mean a mutable array. As youve discovered, you can't alter the number or position of elements in an NSArray
.
Note also that arrayForKey:
will return an NSArray
even if you stored a mutable array in the first place, so when getting the value from defaults you will have to do the following:
NSMutableArray *myData = [NSMutableArray arrayWithArray:[defaults arrayForKey:@"data"]];
Where defaults
is your user defaults object.
Upvotes: 1