When I try to insert an object to my NSMutableArray I am getting a 'Program received signal: SIGABRT' error, however I don't understand why.
Here is my code, specifically it's the insertObject:value that is causing the error.
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionary];
[myDictionary setValue:valueName.text forKey:kValueName];
[myDictionary setObject:subValuesList forKey:kSubValuesList];
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
int position = appDelegate.position;
NSMutableArray *valuesList = [[NSUserDefaults standardUserDefaults] objectForKey:kValuesArray];
[valuesList insertObject:myDictionary atIndex:position];
Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value.
You need to make a mutable copy after you retrieve the array from NSUserDefaults. Luckily for you, NSArray conforms to the NSMutableCopying protocol, so you just have to send a mutableCopy message to the array:
NSMutableArray *valuesList = [[[NSUserDefaults standardUserDefaults] objectForKey:kValuesArray] mutableCopy];
Keep in mind that you own the object returned by mutableCopy as per the Memory Management Rules. In other words, you need to release it when you are done with it.
You have to save and retrieve the array using NSData. Possible dup.
Possible to save an integer array using NSUserDefaults on iPhone?
Related
I have two array one is NSMutableArray and one is NSArray i want to store the contents of NSMutableArray in NSArray but it is not working for me gives exception unrecognised selector sent.
myArray=[[NSArray alloc] initWithArray:appDelegate.surveyAnswersScreenOne];
Note, SurveyAnswerScreenOne is an NSMutableArray
You can do that in many ways -
NSArray * myArray = [appDelegate.surveyAnswersScreenOne copy];
NSArray * myArray = [NSArray arrayWithArray:appDelegate.surveyAnswersScreenOne];
NSArray * myArray = [[NSArray alloc]initWithArray:appDelegate.surveyAnswersScreenOne];
But first of all your appDelegate.surveyAnswersScreenOne should have objects in it.
Have you made object for your appDelegate ?
appDelegate = (yourDelegateClass *)[[UIApplication sharedApplication]delegate];
If yes, then other answers should work!
myArray = [NSArray arrayWithArray:appDelegate.surveyAnswersScreenOne];
From what we see here, it is most likely that your mutable array is nil. Look into the creation of that in you app delegate. If it is created properly, check that it is retained. Is it a strong reference?
#propery(nonatomic, strong) NSMutableArray *surveyAnswersScreenOne;
for one, I would use the convenience method:
myArray = [NSArray arrayWithArray:appDelegate.surveyAnswersScreenOne];
If surveyAnswersScreenOne is a valid array, mutable or otherwise, this should work. Try printing it to the console to be sure. This will return empty array if surveyAnswersScreenOne is nil, where alloc initWithArray will fail.
Check you mutable array like this.
NSLog(#"Mutable array is %#", appDelegate.surveyAnswersScreenOne);
I want to be able to access an array of objects in my iPhone application. The array of objects is populated in the appDelegate of my application and I want to be able to access the array in one of my View Controllers.
I currently set up the array in my appDelegate.h file as follows:
NSArray *listObjArray;
#property (nonatomic, retain) NSArray *listObjArray;
I then populate it with some Strings like this in the AppDelegate:
listObjArray = [NSArray arrayWithObjects:#"Hello", #"How", #"are", nil];
NSLog(#"Array size = %i", [listObjArray count]);
It is synthesized and also released in dealloc. The NSLog returns the correct count here.
In my ViewController class I import the appDelegate like this:
#import "MyaAppDelegate.h"
I then access my appDelegate and the NSArray like this and try to Log the count in my View Controller:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication]
delegate];
NSLog(#"Before array set");
NSArray *newArray = [appDelegate listObjArray];
NSLog(#"After array set");
NSLog(#"array count = %i", [newArray count]);
NSLog(#"After array count");
The logging here gets to "After array set" and then I get "EXC_BAD_ACCESS" on the line where I try to print the count from the array in the View Controller.
The printing of the count works fine from the appDelegate and setting the newArray as the array from the delegate appears to work yet I cant do anything with it then.
Can anyone see what I am doing wrong?
I think your array declaration should be:
NSArray *newArray = [[NSArray alloc] initWithArray:appDelegate.listObjArray]
Be sure to release it after you are done! Though I'm not sure why you want to declare the new array, you could just do:
NSLog(#"array count = %i", [appDelegate.lstObjArray count]);
Hope this helps!
-Karoly
You have a memory issue: listObjArray = [NSArray arrayWithObjects:#"Hello", #"How", #"are", nil]; sets the instance variable directly. Shortly after this line the array gets released again, which results in you accessing a bad memory location in NSArray *newArray = [appDelegate listObjArray];, since it has been freed.
Use self.listObjArray = ... instead when populating the array. This will properly retain the object for you.
Please use the getter if it is sythesized. Since you are not using the getter, it is giving you bad memory access.
Also you should use retain or copy if you want to retain it or copy it. Else both newArray and listObjectArray will point to same memory location causing bad behavior.
NSArray *newArray = [[appDelegate getListObjArray] retain];
Try this
self.listObjArray = [NSArray arrayWithObjects:#"Hello", #"How", #"are", nil];
Allocation should be made on the getter.
Suppose I am holding data in an array like this
wordList = [[NSMutableArray alloc] init];
while ([rs next]) //Some database return loop
{
wordDict = [[NSMutableDictionary alloc] init];
[wordDict setObject:[NSNumber numberWithInt:[rs intForColumn:#"id"]] forKey:#"id"];
[wordDict setObject:[rs stringForColumn:#"word"] forKey:#"word"];
[wordList addObject: wordDict];
[wordDict release];
wordDict = nil;
}
But I want to store this result (i.e. wordList) in SQLite for later use - I guess using NSCoding. How would I do that?
(Feel free to point out any errors in how stuff is being alloc'ed if there are problems there).
If you don’t insist on serialization using NSCoding, there’s a writeToFile:atomically: method both on NSArray and NSDictionary. This will serialize your object into a property list (*.plist). The only catch is that all the objects in the “tree” to be serialized must be NSString, NSData, NSArray, or NSDictionary (see the documentation). I’m not sure how NSNumber fits in, but with a bit of luck it will be serialized and deserialized too. The inverse method that will turn the file back into a dictionary or an array is called initWithContentsOfFile:.
As for your code, I would just use the [NSMutableDictionary dictionary] convenience method that gets you an autoreleased dictionary. It’s shorter than the usual alloc & init and you save one line for the explicit release.
I'm writing an application which uses NSUserDefaults as the data storage mechanism, and am hitting a problem when trying to save data (that conforms to the Property List protocols):
+ (BOOL)storeAlbum:(Album *)album
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *albums = (NSMutableDictionary *)[prefs objectForKey:#"my_adventure_book_albums"];
NSLog(#"Existing albums: %#",albums);
if (!albums)
albums = [NSMutableDictionary dictionaryWithObject:album forKey:#"album"];
else
[albums setObject:album forKey:#"album"];
NSLog(#"%#",album);
[prefs setObject:albums forKey:#"my_adventure_book_albums"];
return [prefs synchronize];
}
I get this output:
2010-06-29 17:17:09.929 MyAdventureBook[39892:207] Existing albums: (null)
2010-06-29 17:17:09.930 MyAdventureBook[39892:207] test
2010-06-29 17:17:09.931 MyAdventureBook[39892:207] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '{
album = test;
}' of class 'NSCFDictionary'.
The description method of Album looks like:
- (NSString *)description
{
// Convert to a NSDictionary for serializing
if (!title) title = #"";
if (!date) date = [NSDate dateWithTimeIntervalSinceNow:0];
if (!coverImage) coverImage = #"";
if (!images) images = [[NSArray alloc] initWithObjects:#"",nil];
//NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:title,date,coverImage,images,nil] forKeys:[NSArray arrayWithObjects:#"title",#"date",#"coverImage",#"images",nil]];
//NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:title,nil] forKeys:[NSArray arrayWithObjects:#"title",nil]];
//return [dict description];
return #"test";
}
All of the commented-out lines have the same result, so I just decided to see if the NSString "test" would work, which it (of course) doesn't.
But the object you put inside the dictionary, an Album* is most likely not a property list object, is it? Every object, all the way down, needs to be a property list object for this to work. A description method isn't good enough to make this happen.
As a workaround, you can use NSCoding and an NSKeyedArchiver to write out your dictionary to an NSData, which you can store among the preferences.
You can only put basic foundation types into a property list. NSUserDefaults writes preferences out as a property list. See here for property list allowed types. In a nutshell, it is numbers, strings, data, dates, and arrays and dictionaries of those. Dictionaries must have string keys.
NSUserDefaults always returns immutable objects, so you can't just cast them to mutable. Do [prefs objectForKey:#"my_adventure_book_albums"] mutableCopy] (and remember to release it when finished).
I have the Array defined below.
NSMutableArray *tempMPArray = [NSMutableArray arrayWithCapacity:16];
for (int i=0; i < chapters; i++)
{
[tempMPArray addObject:[NSNull null]];
}
Every time I use it as a one of the objects of a dictionary below to register default values it crashes with EXC_BAD_ACCESS.
[[NSUserDefaults standardUserDefaults] registerDefaults:myDict];
If I replace the objects in the array with any other object NSNumber etc it works fine. What am I doing wrong with my array that NSUserDefaults rejects it ? The stack trace or NSZombie does not give any additional info.
While the solution may be a "work-around" I don't think it answers the underlying question. By providing a dictionary with [NSNull null] values he is providing NSUserDefaults with a valid dictionary. Why is it crashing? Is it something he is doing "wrong" or is it a bug in registerDefaults?
There may be circumstances where it is important to know whether say a user has entered a value (ie there is a valid string) or not entered a value (null) and the method of creating a "valid but empty string" can't determine if the empty string was because the user created a string with no characters or if he had never created a string at all. You may want different logic in these two cases.
I'm in the same boat, I have an NSUserDefault value I want to be [NSNull null] and everything I've read suggests the "right" way to put a null value in a dictionary is with [NSNull null] and my dictionary creates fine. But registerDefaults with this valid dictionary causes a crash. That suggests a bug in the implementation of registerDefaults doesn't it? What is wrong with the following and why does it crash?
NSArray *defaultValues = [NSArray arrayWithObjects:[NSNull null], nil];
NSArray *CurrentKeys = [NSArray arrayWithObjects: #"NullKey", nil];
NSDictionary *resourceDict = [NSDictionary dictionaryWithObjects:defaultValues forKeys:CurrentKeys];
[[NSUserDefaults standardUserDefaults] registerDefaults:resourceDict];
Ultimately, i think the answer is that the userDefaults get written out as a plist and plists don't support NSNull. if that's the case, the documentation for registerDefaults should say that only plist object types are allowed in the dictionary
Here's a better solution!
Define a static after #implementation
NSString *const Null = #"";
Then
NSMutableArray *tempDSArray = [NSMutableArray arrayWithCapacity:16];
for (i=0; i < chapters; i++)
{
[tempDSArray addObject:Null];
}
Everything else should work fine!