Test NSmutable array from plist before saving - objective-c

I'm trying to made a cocoa app that read-write to a .plist file.
I can retrieve informations from the .plist, write into, but when a key (only with strings) is empty, the app don't write to the plist.
here a sample:
-
(IBAction)saveBoot:(id)sender {
NSString *errorDesc;
NSString *bootPath = #"/myplist.plist";
NSMutableDictionary *plistBootDict =
[NSMutableDictionary dictionaryWithObjects:
[NSMutableArray arrayWithObjects:
Rescan,
RescanPrompt,
GUI,
InstantMenu,
DefaultPartition,
EHCIacquire,
nil]
forKeys:[NSMutableArray arrayWithObjects:
#"Rescan",
#"Rescan Prompt",
#"GUI",
#"Instant Menu",
#"Default Partition",
#"EHCIacquire",
nil]];
NSData *plistBootData = [NSPropertyListSerialization
dataFromPropertyList:plistBootDict
format:NSPropertyListXMLFormat_v1_0
errorDescription:&errorDesc];
if (bootPath) {
[plistBootData writeToFile:bootPath atomically:NO];
}
else {
NSLog(errorDesc);
[errorDesc release];
}
}
#end
I think i need a loop to check if each key is empty or not (and remove it if empty),
but i've tried different (objectEnumerator, objectForKey:..etc) method whitout success.
If someone can help a beginner like me,
thanks in advance.
Ronan.

The problem is probably that because nil is the terminator for variable argument lists, so if, say, RescanPrompt is nil, the object array will only contain up until that part (so you can't "remove if empty" since it won't exist in the dictionary in the first place). You should probably construct your dictionary piece by piece; something like:
NSMutableDictionary *plistBootDict = [NSMutableDictionary dictionary];
if (Rescan)
[plistBootDisc setObject:Rescan forKey:#"Rescan"];
if (GUI)
[plistBootDisc setObject:GUI forKey:#"GUI"];
// etc
(Also, there's no reason to be using NSMutableArray or NSMutableDictionary if you're never going to be mutating them later.)

Related

Create an NSMutableArray that contains several NSMutableDictionary objects

I've looked around and seen several postings concerning sorting NSMutableArray's that contain NSDictionaries, but haven't been able to find some concrete examples of how to actually make an NSMutableArray composed of NSDictionaries.
I am using NSUserDefaults to keep track of a user's preferences for several different items. The NSMutableArray will be used to keep track of the total items, and the NSDictionaries are for the individual preferences concerning each item.
I've written these methods to keep track of items in my preferences class, but I'm not too sure how to initialize the NMutableArray to contain NSDictionaries.
-(NSMutableArray *)deviceListArray
{
return [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"device_list_array"];
}
-(void) setDeviceListArray:(NSMutableArray *)deviceListArray
{
[[NSUserDefaults standardUserDefaults] setObject:deviceListArray forKey:#"device_list_array"];
}
If anyone could point me in the right direction, I would really appreciate it. Thank you very much! Or if someone has a better strategy for keeping track of items, each with different preferences, then that would be awesome too!
Thanks!!
Once you hand an object of to userDefaults, it owns that object - so you cannot go changing properties of dictionaries inside it.
What you can do is a two pass copy, where you have a local mutable array with mutable dictionaries in it. You would create a new mutable array of the same size, then for each mutable dictionary, call [NSDictionary dictionaryWithDictionary:], adding the new non-mutable dictionary to the new array.
If you have mutable objects buried in the dictionaries, well, you need to do the same for that.
All that said, if you have such a huge amount of stuff I suspect you have no properly thought of how to use the defaults system. I almost always just save strings, numbers, colors etc.
EDIT: code
NSMutableArray *array = [NSMutableArray arrayWithCapacity:10];
for(int i=0; i<10; ++i) {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:10];
// add stuff to the dictionary
[array addObject:dict];
}
// later on want to change second dictionary:
NSMutableDictionary *dict = [array objectAtIndex:1];
// fool around with dict
// no need to re-save it in array, since its mutable
Not sure if this is what you were looking for:
#define kDeviceKey1 #"DeviceKey1"
#define kDeviceKey2 #"DeviceKey2"
#define kDeviceKey3 #"DeviceKey3"
#define kDeviceKey4 #"DeviceKey4"
#define kDeviceID #"DeviceID"
NSMutableArray *devices = [[NSMutableArray alloc]init];
NSMutableDictionary *deviceInfo = [[NSMutableDictionary alloc]init];
// create a dictionary record for earch device which contains thing...
// probably employ some kind of loop
deviceInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:1], kDeviceID,
// #"DeviceName1", kDeviceID, // or this
#"whateverthing1forDevice1", kDeviceKey1,
#"whateverthing2forDevice1", kDeviceKey2,
#"whateverthing3forDevice1", kDeviceKey3,
#"whateverthing4forDevice1", kDeviceKey4,
nil];
[devices addObject:deviceInfo];
// this is just an example, you would have some kind of loop to replace "whateverthing1forDevice1" with actual data
deviceInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:2], kDeviceID,
// #"DeviceName2", kDeviceID, // or this
#"whateverthing1forDevice2", kDeviceKey1,
#"whateverthing2forDevice2", kDeviceKey2,
#"whateverthing3forDevice2", kDeviceKey3,
#"whateverthing4forDevice2", kDeviceKey4,
nil];
[devices addObject:deviceInfo];
NSLog(#"devices: %#", devices);

Retrieving NSArray From an NSDictionary

I am trying to get an array full of my data, I keep getting an BAD_ACCESS error when I run this though at the calling the array which I have not included here but I even commented that code out and tried just calling it to the log and still get the BAD_ACCESS error. The array is stored in a dictionary that contains a one key that is a number. I am not sure what I am doing wrong here.
ISData *is = [[ISData alloc] init];
NSDictionary *dic = [is getData:#"right" : isNumber];
NSArray *array = [[NSArray alloc] initWithArray:[dic valueForKey:#"2"]];
NSString *out = [array objectAtIndex:0];
How the dictionary is created:
NSNumber* key = [NSNumber numberWithInt:isNumber];
NSArray *values = [NSArray arrayWithObjects:[NSString stringWithUTF8String:name], [NSString stringWithUTF8String:desc], [NSString stringWithUTF8String:intent], nil];
[dic setObject:values forKey:key];
You don't say exactly where it crashes, and you don't have an obvious crashing bug here, so it's hard to diagnose your actual issue. This could be a memory management thing that's outside the code you've presented. But a couple things are going on here that are suspicious:
You should never have a bare [MyClass alloc] without the -init call. Your init should call super's init, which is responsible for setting up the new object.
Your -valueForKey: should be -objectForKey:. The difference is probably unimportant in this case, but the former is used for "KVC" coding, which you're not using. If you set it as object, get it as object.
Your #"2" as the key into the dictionary doesn't match your input, which is an NSNumber. NSNumbers are not string versions of numbers, so you're unlikely to find any value there. Instead, use the same [NSNumber numberWithInt:2] pattern.
It is most likely that your array is empty. You can try print NSLog(#"count = %d", array.count); to see if that's the case.
If your dic is set up in the second block of code, then what's that NSDictionary *dic = [is getData:...] thing in the first block?
And is there a reason you cannot set up your array directly? Is there a reason for you to use a dictionary when it has only one key?

Objective C - EXC_BAD_ACCESS on [NSArray count] but can't see how

I'm working on a piece of code that GETs a URL and parses the contents for data between a asset of tags. In this case, it's looking for the code between and . When the URL body returned doesn't contain those tags, the cullXML: method returns an empty array like this:
return [NSArray arrayWithObjects: nil];
I check to be sure that the returned array has objects with:
if ( matchesXML.count ) {
In my debug code, I check twice. The first time, it works fine. The second time, just a couple lines later, it crashes. I can't see why. The lines look the same to me.
What am I missing?
A bigger chunk of the code is included below. Thanks!
if (self.newResults) {
NSString *urlResult;
NSArray *matchesXML;
NSArray *match;
NSDictionary *currentResult;
NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
NSArray *returnedObjects;
NSArray *dictionaryKeys;
NSMutableArray *currentResultObjects;
int i = 0;
// determine tournament type, because the fields are different per type
NSString *tournamentType;
tournamentType = [[AFMethods tournamentTypeFromId:self.inputTournamentId] objectAtIndex:0];
urlResult = [NSString stringWithFormat:#"%#", responseHandle];
[responseHandle release];
NSLog(#"urlResult retrieved: %#", urlResult);
matchesXML = [AFMethods cullXML: urlResult forTag: #"matches"];
NSLog(#"matches loaded: %#", matchesXML);
NSLog(#"matchesXML.count %i", matchesXML.count);
if ( matchesXML.count ) {
NSLog(#"not nil");
}
NSLog(#"just before tested");
if ( matchesXML.count ) {
NSLog(#"tested");
I found the issue!
It wasn't crashing where I thought. It was a couple lines later. I was releasing an auto-released object. It must have been a left-over line from a previous organization of the code.
I removed the release and it's working perfectly again.
My guess is that you're not using the return statement you listed, but rather one that returns a different NSArray, only this one isn't retained. The first NSLog causes heap to be used, stomping on the array object.

Objective-C identifier from NSString

I want to pass an NSString to a method and have that particular NSString name a new NSSMutableArray. Confusing? Programmatically looks like this:
+ (void)newMutableArrayWithName:(NSString*)theArrayName
{
NSLog(#"Creating an array that is named: %#",theArrayName);
NSMutableArray* theArrayName = [[NSMutableArray alloc] init];
}
Unfortunately, "theArrayName" is not affiliated with the argument passed to the method. Is there any way this is achievable?
The name of a variable is used by the compiler, and is set at compile-time, not at run time.
If you need to be able to associate a label with an array, I suggest that you use an NSDictionary to do something like this
NSString *theArrayName = #"My Cool Array";
NSMutableArray *theArray = [NSMutableArray array];
NSDictionary *theDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
theArray, theArrayName, nil];
You could have multiple "named" arrays in the dictionary, if you wanted, and could access them by the names that you gave them
[theDictionary objectForKey:#"My Cool Array"];
Look into key-value coding for setting the values of existing properties by the property's name, but it appears it can't create a new property. For that, you should just use a dictionary.

Sorting a mutable array using a dictionary key

I am trying to create a simple mutable array with a single key ("dayCounter") that I intend to use for sorting. I've read loads of examples on line, but no joy.
So I create this array. Note the first entry is a NSDictionary object. (The other objects are text)
cumArray = [NSMutableArray arrayWithObjects:[NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter] forKey:#"dayCounter"],[[dailyArray objectAtIndex:x]objectAtIndex:0],[[dailyArray objectAtIndex:x]objectAtIndex:1],[[dailyArray objectAtIndex:x]objectAtIndex:2], nil],nil];
I save the array in a plist and everything looks great after the load.
However, when I come to sort the array, the program crashes. I have tried every combination of the following:
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"dayCounter" ascending:YES];
[cumArray sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
Do I need a dictionary item to act as a key? Can I sort on the first object any easier? Any help is much appreciated.
Sometimes using too many nested expressions can obscure what's really going on. For example, the 'simple' mutable array you created actually contains a nested mutable array, rather than directly containing the dictionaries you're trying to sort.
So instead of this:
cumArray = [NSMutableArray arrayWithObjects:[NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter] forKey:#"dayCounter"],[[dailyArray objectAtIndex:x]objectAtIndex:0],[[dailyArray objectAtIndex:x]objectAtIndex:1],[[dailyArray objectAtIndex:x]objectAtIndex:2], nil],nil];
try doing this
NSDictionary *dict1 = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter]
forKey:#"dayCounter"]
NSArray *objs = [dailyArray objectAtIndex:x];
NSDictionary *dict2 = [objs objectAtIndex:0];
NSDictionary *dict3 = [objs objectAtIndex:1];
NSDictionary *dict4 = [objs objectAtIndex:2];
// Note: You might want to temporarily log the values of dict2 - 4 here to make sure they're
// really dictionaries, and that they all actually contain the key 'dayCounter'.
cumArray = [NSMutableArray arrayWithObjects:dict1, dict2, dict3, dict4, nil];
Assuming that you really have a mutable array of dictionaries, each of which contains the key dayCounter, the sort descriptor you showed in your example should work just fine.
Your setup makes no sense. You are saying yourself that only the first object in the array is a dictionary that contains the key `#"dayCounter" ("The other objects are text"). How is it supposed to be sorted if only one object contains the sort criteria?
You need to sort the array with a method, like - (NSComparisunResult)compareDict
If you have to compare 2 dictionaries and determine which one should be ordered above the other ( NSOrderedAscending ) then you need to "extend" NSDictionary:
#interface NSDictionary (SortingAdditions) {}
- (NSComparisonResult)compareTo:(NSDictionary *)other;
#end
#implementation NSDictionary (SortingAddictions)
- (NSComparisonResult)compareTo:(NSDictionary *)other
{
if( [self count] > [other count] )
{ return NSOrderedAscending; }
}
#end
This method will sort NSDictionaries according to the amount of objects that they contain.
Other values you can return here are: NSOrderedDescending and NSOrderedSame.
Then you can sort the mutable array with:
[SomeMutableArray sortUsingSelector:#selector(compareTo:)];
Keep in mind that every object in the array will need to be an NSDictionary, otherwise you will get an exception: unrecognized selector sent to instance blabla
You can do the same thing for any type of object, if the array contains both NSStrings, NSNumbers and NSDictionaries you should take a different approach