i am trying to add an object into a nsuserdefault, but i get this crash
"[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object"
its crashing on this line:
[currentFav addObject:incomingBabe];
I have no idea why its crashing, its working on my other project.
here is my code
-(IBAction)favorite {
NSUserDefaults *standardDefault = [NSUserDefaults standardUserDefaults];
NSMutableArray *currentFav = [[NSUserDefaults standardUserDefaults]objectForKey:#"fav"];
NSLog(#"strings stored = %#",currentFav);
NSMutableArray *newFav = [NSMutableArray arrayWithObject:[NSString stringWithFormat:#"bikini%02d.jpeg",self.currentNumber]];
if (currentFav == NULL){
currentFav = [[NSMutableArray alloc]init];
}
for(NSString *incomingBabe in newFav){
BOOL hasStringAlready = NO;
for(NSString *currentFavorite in currentFav){
if([currentFavorite isEqualToString:incomingBabe]){
hasStringAlready = YES;
NSLog(#"has string already");
break;
}
}
if (!hasStringAlready) {
[currentFav addObject:incomingBabe];
hasStringAlready = YES;
}
}
[standardDefault setObject:currentFav forKey:#"fav"];
[standardDefault synchronize];
}
Basically it says you are trying to use a method from NSMutableArray on NSArray.
This is because "Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value."
NSMutableArray *currentFav = [[NSUserDefaults standardUserDefaults]objectForKey:#"fav"];
will return an array, not mutable array. You should make a mutable copy of it.
NSMutableArray *currentFav = [[[NSUserDefaults standardUserDefaults]objectForKey:#"fav"] mutableCopy];
You can get the reason of your problem from 1 floor. You can use his method to solve your problem, or like this:
NSMutableArray *currentFav = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults]objectForKey:#"fav"]];
Related
I have this code
[[self.client dataClient] getEntities:#"book" query:nil
completionHandler:^(ApigeeClientResponse *result) {
if (result.transactionState ==kApigeeClientResponseSuccess) {
_objects = result.response[#"entities"];
} else {
_objects = #[]; //"Incompatible pointer types assigning to NSMutableArray from NSArray"
}
[self.tableView reloadData];
}];
It shows me error "Incompatible pointer types assigning to NSMutableArray from NSArray"
_objects is implemented in NSArray and returns an NSArray even when called on an NSMutableArray.
assign [NSMutableArray array];
You are trying to assing a NSArray (#[]) to a variable of type NSMutableArray.
Replace:
_objects = #[];
with:
_objects = #[].mutableCopy;
Even you do not mention an error in the first if clause, you have to replace this also.
_objects = [NSMutableArray arrayWithArray:result.response[#"entities"]];
Hi I am trying to store an array into NSUserDefaults but I am having troubles. The method accepts an NSDictionary which I will store into an array that i will store into NSUSerDefaults. The problem is when I make a mutableCopy it says its a dictionary and not of type NSMutable array? This method is the first time I would be calling NSUserDefaults so I am unsure why the error is happening? Here is the code thanks
+(void) getRecentPhoto:(NSDictionary *)recentPhoto{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
//stores it as a dictionary? error happens here
NSMutableArray* recentPhotos = [[defaults objectForKey:#"recentPhoto"] mutableCopy];
NSLog(#"%#", [recentPhotos class]);
if(!recentPhotos) recentPhotos = [NSMutableArray array];
BOOL copy = NO;
//these will crash the program
NSLog(#"%#", [[recentPhotos objectAtIndex:0] objectForKey:#"id"]);
NSLog(#"%#", [recentPhoto objectForKey:#"id"]);
//this checks if it has been stored before by using an id key
for(int i =0; i < [recentPhotos count]; i++){
if ([[[recentPhotos objectAtIndex:i] objectForKey:#"id"] isEqualToString:[recentPhoto objectForKey:#"id"]] ) {
copy = YES;
}
}
if(copy ==NO)
[recentPhotos addObject:recentPhoto];
[defaults setObject:recentPhoto forKey:#"recentPhoto"];
[defaults synchronize];
}
This is the error
NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector
I believe the problem is, in the end of this method, you try to store recentPhoto, which is a dictionary, into user default instead of recentPhotos, the mutable array you want to store.
Actually, I think it will not crash at the first time this method is called since recentPhoto has not been stored in user default. But after that, it will.
I'm strugglig with the following code. I don't undesratnd what's wrong with it.
Code is commented with respect to the crash:
- (IBAction) SavePreset: (id) sender
{
NSString *presetName = [nameCombo stringValue]; // nameCombo is a NSComboBox*
NSUserDefaults *vmDefaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *projectionPresets = [vmDefaults objectForKey: kVmGeorefPresetKey];
BOOL doSave = YES;
NSString *dictEntry = [projectionPresets objectForKey: presetName];
if (dictEntry) {
// this branch is not tested yet, plan to test when the rest is working.
int userChoice;
userChoice = NSRunAlertPanel( #"Save Preset",
#"This preset (%s) already exists, modify?",
#"OK", #"Cancel", nil, presetName);
doSave = (userChoice == NSAlertDefaultReturn);
if (doSave) {
[nameCombo addItemWithObjectValue: presetName];
}
}
if (doSave)
{
// projParamText is of class NSTextField*
NSString *presetParam = [projParamText stringValue];
// Up to this point, everything works as expected
// But, the following statement crashes silently.
[projectionPresets setObject: presetParam forKey: presetName];
// and the subsequent code is never executed
[savePresetButton setEnabled: NO];
}
}
I wonder whether he NSString* returned from [NSControl stringValue] returns a pointer to an internal string reperesentaion or a new NSString that will not change if I edit the text of the NSTextField later on.
Found the culprit. The following statment is from the NSUserDefaults documentation:
Values returned from NSUserDefaults are immutable, even if you set a
mutable object as the value. For example, if you set a mutable string
as the value for "MyStringDefault", the string you later retrieve
using stringForKey: will be immutable.
The workaround is do create a new preset dictioary from the old immutable one, modify that and store it back with the user defaults.
try [projectionPresets setValue: presetParam forKey: presetName];
Also NSLog your presetName and presetParam and see if any of those are nil values.
To setobject in an NSMutableDictionary you have to first do
NSMutableDictionary *projectionPresets = [[NSMutableDictionary alloc] init];
Then only you can setobject for an NSMutableDictionary. The mutable dictionary should be an absolute mutable.
I have a leak in the following code:
- (void)viewDidAppear:(BOOL)animated {
//If Home-Theme
if (themeIndex == 0) {
NSUserDefaults *pref = [NSUserDefaults standardUserDefaults];
NSMutableArray *thisArray = [[NSMutableArray alloc] init];
thisArray = [[pref objectForKey:#"Themes"] mutableCopy];
[thisArray release];
}
}
the leak is at NSMutableArray.
I have try'd some different workarounds but nothing is help.
Maybe there is someting wrong with the NSUserDefaults?
any ideas?
thank you
xnz
NSMutableArray *thisArray = [[NSMutableArray alloc] init];
That is leaking since you never release that instance, just assign a new one in the next line. Replace it with:
NSMutableArray *thisArray = [[pref objectForKey:#"Themes"] mutableCopy];
You are allocating a NSMutableArray and the changing the reference to another array.
You probably want something like this:
- (void)viewDidAppear:(BOOL)animated {
//If Home-Theme
if (themeIndex == 0) {
NSUserDefaults *pref = [NSUserDefaults standardUserDefaults];
NSMutableArray *thisArray = [[pref objectForKey:#"Themes"] mutableCopy]];
// do something with thisArray
[thisArray release];
}
}
you alloc thisArray and then overwrite the reference to it with a mutable copy from pref. Either do autorelease or just remove the unnecessary NSMutableArray allocation
Can you show me the syntax or any sample programs to archive an NSArray of custom objects in Objective-C?
Check out NSUserDefaults.
For Archiving your array, you can use the following code:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:myArray] forKey:#"mySavedArray"];
And then for loading the custom objects in the array you can use this code:
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *savedArray = [currentDefaults objectForKey:#"mySavedArray"];
if (savedArray != nil)
{
NSArray *oldArray = [NSKeyedUnarchiver unarchiveObjectWithData:savedArray];
if (oldArray != nil) {
customObjectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
} else {
customObjectArray = [[NSMutableArray alloc] init];
}
}
Make sure you check that the data returned from the user defaults is not nil, because that may crash your app.
The other thing you will need to do is to make your custom object to comply to the NSCoder protocol. You could do this using the -(void)encodeWithCoder:(NSCoder *)coder and -(id)initWithCoder:(NSCoder *)coder methods.
If you want to save to a file (rather than using NSUserDefaults) you can use -initWithContentsOfFile: to load, and -writeToFile:atomically: to save, using NSArrays.
Example:
- (NSArray *)loadMyArray
{
NSArray *arr = [NSArray arrayWithContentsOfFile:
[NSString stringWithFormat:#"%#/myArrayFile", NSHomeDirectory()]];
return arr;
}
// returns success flag
- (BOOL)saveMyArray:(NSArray *)myArray
{
BOOL success = [myArray writeToFile:
[NSString stringWithFormat:#"%#/myArrayFile", NSHomeDirectory()]];
return success;
}
There's a lot of examples on various ways to do this here: http://www.cocoacast.com/?q=node/167