Add Mutable Dictionary to a Mutable Dictionary for conversion to JSON - xcode

I am trying to build a dictionary which has as dictionary within it (eventually I hope to convert to a JSON). The problem is I am having problems building it.
So far I have this, what it should do is build a small dictionary with keys and add it to a larger dictionary, reset and then load the small dict and then add it to the large one.
NSMutableDictionary *nestedList = [[NSMutableDictionary alloc]init];
NSMutableDictionary *nestedSections = [[NSMutableDictionary alloc] init];
[nestedList addEntriesFromDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:46], #"menuHeight",
#"editText", #"menuMethod",
[NSNumber numberWithInt:1], #"menuOption",
nil]];
[nestedSections addEntriesFromDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
nestedList, "#Basic",
nil]];
[nestedList removeAllObjects];
[nestedList addEntriesFromDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:92], #"menuHeight",
#"sendText", #"menuMethod",
[NSNumber numberWithInt:1], #"menuOption",
nil]];
[nestedSections addEntriesFromDictionary:[NSDictionary dictionaryWithObjectsAndKeys:
nestedList, "#Pro",
nil]];
I then hoped to address like so;
NSString *string = [[nestedSections objectForKey:#"Pro"] objectForKey:#"menuMethod"];
NSLog(#"Method is : %#", string);
Log would hope to read sendText
The first dictionary builds fine but as soon as I try and add it to the second t bums out with EXC_BAD_ACCESS
I think it is a memory addressing problem because they are both mutable but I am not sure, maybe nestedList should not be mutable. Any help appreciated.
Ultimately I would like to convert this to a JSON like;
{
"Basic":
{
"menuHeight":"46",
"menuMethod":"editText",
"menuOption":"1",
},
"Pro":
{
"menuHeight":"96",
"menuMethod":"sendText",
"menuOption":"1",
}
}

A. NSMutableDictionary does not copy the values (only the keys). Therefore you add the same dictionary two times and change both (= the one) when removing objects and so on. Beside this in your sample JSON the numbers looks like strings not like numbers. I think, that this is a typo.
B. Adding modern Objective-C for better readability it should look like this:
NSDictionary *basicDictionary =
#{
#"menuHeight" : #46,
#"menuMethod" : "editText",
#"menuOption : #1
}
NSDictionary *proDictionary =
#{
#"menuHeight" : #96,
#"menuMethod" : "sendText",
#"menuOption : #1
}
NSDictionary *nestedSections = #{ #"Pro" : proDictionary, #"Basic" : basicDictionary };

Related

Find out if .png file is a screenshot?

When I get the attributes of a specific file with the following code:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *attributes = [fileManager attributesOfItemAtPath:p error:nil];
Is there an attribute to know if it's a screenshot or not?
Right now I'm using this awkward piece of code:
if ([fileExtension isEqualToString:#"png"]) {
NSMutableArray *separatetFilename;
separatetFilename = [NSMutableArray arrayWithArray:[fileName componentsSeparatedByString:#" "]]; /* screenshots have multiple spaces in their names, I split them up to use the information */
if ([separatetFilename count] == 4) { /* screenshots names have 4 parts when splittet by spaces */
if ([[separatetFilename objectAtIndex:0] isEqualToString:#"Bildschirmfoto"]) { /* Bildschirmfoto = Screenshot in German */
/* Do Something */
}
}
}
With this solution I would have to put in localized Strings for the "Screenshot" string... I searched the documentary but didn't find anything. Is there a "isScreenshot" flag or something I could read?
Your question "Is there a "isScreenshot" flag or something I could read?" and the answer is "YES".
I know of two ways to get the answer:
a) ask the NSFile~Manager
b) ask for metadata.
You already used:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *attributes = [fileManager attributesOfItemAtPath:p error:nil];
If you now have a look at the keys of this dictionary e.g. with
NSLog( #"the keys: %#", [attributes allKeys] );
you will find the key #"NSFileExtendedAttributes*". The value of this key is a dictionary with keys like com.apple.metadata:kMDItemIsScreenCapture or com.apple.metadata:kMDItemScreenCaptureType or .... This is what you asked for. The corresponding values are NSData-objects with a binary property list. Evaluating these plist give something like 1 (it is a screenshot) and window for a window screenshot or selection for a part of the window.
Looking at the metadata can be done with:
MDItemRef item = MDItemCreate( kCFAllocatorDefault, (CFStringRef)p );
If you only need the above mentioned values create a list (an NSArray) with the corresponding keys:
NSArray *ary = [NSArray arrayWithObjects:
#"kMDItemIsScreenCapture", #"kMDItemScreenCaptureType", nil];
NSDictionary *dict =
(NSDictionary *)MDItemCopyAttributes( item, (CFArrayRef)ary );
and test what it returns;
NSLog( #"the metadata are %#", dict );
In this case the returned values are __NSCFBoolean (i.e. NSNumber) and __NSCFString (i.e. NSString) which is a bit simpler to work with than a binary plist.

Building up an array an element at a time

Currently I'm populating an array in one line, e.g.
self.monthMonths = [[NSArray alloc] initWithObjects:#"January", #"February", #"March", #"April", #"May", #"June",#"July",#"August",#"September",#"October",#"November",#"December", nil];
What is the syntax to add these elements one at a time as I want to pull the data from a database. I'm using the months of the year as an example.
while([results next]) {
NSString *months = [results stringForColumn:#"month"];
self.month = [[NSArray alloc] initWithObjects:#"month",nil];
//[NSArray
NSLog(#"Month: %#",month);
}
Create an NSMutableArray and add the objects to it one by one with addObject
You need to use NSMutableArray instead, and call -addObject:

Sort a NSMutableArray in objective-c?

I am working on NSMutable Array containing list of "First Name" in it.I want to sort it alphabatically.
I tried this code
NSSortDescriptor * sortFriend = [[[NSSortDescriptor alloc] initWithKey:kfirstName ascending:YES] autorelease];
NSArray * descriptors = [NSArray arrayWithObject:sortFriend];
NSArray * sorted = [Friendsarr sortedArrayUsingDescriptors:descriptors];
correct me if i am wrong.I do have an array of names also if that could be used.
Thanks
I tried the code
NSSortDescriptor * sortFriend = [[[NSSortDescriptor alloc] initWithKey:kfirstName ascending:YES selector: #selector(caseInsensitiveCompare:)] autorelease];
NSArray * descriptors = [NSArray arrayWithObject:sortFriend];
NSArray * arrmp = [temparray sortedArrayUsingDescriptors:descriptors];
But still my result contain 2 'k' chars. one 'k' and 'K'.I want to have case insensitive result
If your NSMutableArray only contains objects of type NSString, simply do:
[myMutableArray sortUsingSelector:#selector(compare:)];
You can sort NSMutable array case insensitively by this code
NSSortDescriptor *sorter=[[[NSSortDescriptor alloc] initWithKey:nil ascending:YES selector:#selector(caseInsensitiveCompare:)]autorelease];
NSArray *sortdescriptor=[NSArray arrayWithObject:sorter];
[cpy_arr_Service_Name sortUsingDescriptors:sortdescriptor];
I found the solution of sorting NSMutableArrays with sample code which can be found on the site below.
http://www.icodeblog.com/2010/12/10/implementing-uitableview-sections-from-an-nsarray-of-nsdictionary-objects/
I hope it help others to as it provides indexed sorting of a grouped table view using an array as the datasource

Sort a NSMutuableArray

I have a NSMutableArray that is loaded with a inforamtion from a dictionary...
[self.data removeAllObjects];
NSMutableDictionary *rows = [[NSMutableDictionary alloc] initWithDictionary:[acacheDB.myDataset getRowsForTable:#"sites"]];
self.data = [[NSMutableArray alloc] initWithArray:[rows allValues]];
There are two key value pairs in the rows dictionary.
I need to sort the self.data NSMutableArray in alphabetical order.
How is this accomplished??
thanks
tony
If the values are plain strings you can use the following to create a sorted array:
NSArray *sorted = [values sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
This should do:
[self.data removeAllObjects];
NSArray *values = [[acacheDB.myDataset getRowsForTable:#"sites"] allValues];
NSSortDescriptor *alphaDescriptor = [[NSSortDescriptor alloc] initWithKey:#"DCFProgramName" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *sortedValues = [values sortedArrayUsingDescriptors:[NSMutableArray arrayWithObjects:alphaDescriptor, nil]];
[alphaDesc release];
[self.data addObjectsFromArray:sortedValues];
There's no need to clear an NSMutableArray if you're replacing it shortly afterwards.
There's no need to create an additional NSMutableDictionary, if you're not modifying anything in it.
There's no need to create an additional NSMutableArray, if you could just as well just add the values to the existing one.
Also: There are some serious memory leaks in your code. (2x alloc + 0x release = 2x leak)
Edit: updated code snippet to reflect OP's update on data structure.

Setting QTMovie attributes

I'm trying to create a QTVR movie via QTKit, and I've got all the frames in the movie. However, setting the attributes necessary doesn't seem to be having any effect. For example:
NSNumber *val = [NSNumber numberWithBool:YES];
[fMovie setAttribute:val forKey:QTMovieIsInteractiveAttribute];
val = [NSNumber numberWithBool:NO];
[fMovie setAttribute:val forKey:QTMovieIsLinearAttribute];
If I then get the value of these attributes, they come up as NO and YES, respectively. The movie is editable, so I can't understand what I'm doing wrong here. How can I ensure that the attributes will actually change?
What I do when I want to export a Quicktime movie is something like the following:
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], QTMovieExport,
[exportSettings objectForKey: #"subtype"], QTMovieExportType,
[exportSettings objectForKey: #"manufacturer"], QTMovieExportManufacturer,
[exportSettings objectForKey: #"settings"], QTMovieExportSettings,
nil];
BOOL didSucceed = [movie writeToFile: tmpFileName withAttributes:dictionary error: &error];
Those attributes are documented as things you can read but not write. However, you might be able to set them when you create the movie, with initWithAttributes:error:.

Resources