Store key / value of NSMutableDictionary to another NSMutableDictionary - objective-c

So I have three NSMutableDictionary's like this:
.h file
NSMutableDictionary *myContainer;
NSMutableDictionary *myD1;
NSMutableDictionary *myD2;
#property (nonatomic, retain) NSMutableDictionary *myContainer;
#property (nonatomic, retain) NSMutableDictionary *myD1;
#property (nonatomic, retain) NSMutableDictionary *myD2;
.m file
#synthesize myContainer;
#synthesize myD1;
#synthesize myD2;
( init )
self.myContainer = [[NSMutableDictionary alloc] init];
self.myD1 = [[NSMutableDictionary alloc] init];
self.myD2 = [[NSMutableDictionary alloc] init];
Now I want to add values or positions in the dictionary to myContainer from myD1 and myD2
Pseudo:
[myD1 setValue:foo forKey:#"bar"];
[foo retain];
[myD2 setValue:hello forKey:#"world"];
[hello retain];
So my question is how do I add specific key / value to myD1 and / or myD2 to myContainer? And then retrieve the key / value from them as well?
The below looks like what I need but I'm a newbie and the format I have differs.
Coming from PHP here is how I would structure this:
$myContainer = array();
$myD1 = array();
$myd2 = array();
$myD1['bar'] = 'foo';
$myD2['world'] = 'hello';
$myContainer['common_index'] = array($myD1, $myD2);
// Alternative
//$myContainer['common_index'] = array(0 => $myD1, 1 => $myD2);
// Retrieving values from $myD1
echo "Value: ".$myContainer['common_index'][0]['bar']."\n";
echo "Value: ".$myContainer['common_index'][1]['world']."\n";
// Alternative
foreach($myContainer['common_index'] as $array) {
foreach($array as $index => $value) {
echo "Index: {$index} Value: {$value} \n";
}
}
Output:
Value: foo
Value: hello
Index: bar Value: foo
Index: world Value: hello
Related:
NSMutableDictionary with single key holding many values in Objective-C programming

Add your myD1 myD2 dictionaries in an Array and set it to the myContainer dictionary as below :
NSMutableArray *array = [NSMutableArray arrayWithObjects:myD1, myD2, nil];
[myContainer setObject:array forKey:#"common_index"];
And for retreiving them :
NSMutableDictionary *myD1Retrieved = [[myContainer objectForKey:#"common_index"] objectAtIndex:0];
NSMutableDictionary *myD2Retrieved = [[myContainer objectForKey:#"common_index"] objectAtIndex:1];

To add data to myContainer:
[myContainer setValue:[mD1 valueForKey:#"bar"] forKey:#"bar"];
[myContainer setValue:[mD2 valueForKey:#"world"] forKey:#"world"];
For retrieval from myContainer:
Object *firstObject = [myContainer valueForKey:#"world"];
Object *secondObject = [myContainer valueForKey:#"bar"];
Object stands for the type of value for world and bar keys.
go on..

Related

Unable to create mutable copy of NSDictionary

UPDATE: Now working (added fixes as suggested - Thanks!)
I've been trying to clone an NSDictionary of employee info. The main NSDictionary is created in a different class and passed along in prepareForSegue. I want to be able to create a mutable copy of that NSDictionary in another class which can then update the employee info and send it off to another class for processing so I still have the original unchanged dataset to work with at a later time. I've found a few different examples on Stack, but nothing I could get working. When I break on the btn_click method and examine the local pp object after the ..objectForKey call, pp is still nil. What have I done wrong here?
obj_person.h
#import <Foundation/Foundation.h>
#interface obj_person : NSObject
#property (strong,nonatomic) NSString *personID;
#property (strong, nonatomic) NSString *personName;
#property (strong, nonatomic) NSString *personTitle;
#end
obj_person.m
#import "obj_person.h"
#implementation obj_person
#synthesize personID = _personID;
#synthesize personName = _personName;
#synthesize personTitle = _personTitle;
#end
viewcontroller.m
#import "ViewController.h"
#import "obj_person.h"
#interface ViewController ()
#end
#implementation ViewController
int mCounter = 1;
NSMutableDictionary *mCopy;
NSMutableDictionary *mNsd;
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *arnames = [[NSArray alloc] initWithObjects:#"mary", #"jane", #"stan", #"cartman", nil];
NSArray *arkeys = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2],[NSNumber numberWithInt:3], [NSNumber numberWithInt:4], nil];
mNsd = [[NSMutableDictionary alloc] initWithCapacity:[arnames count]];
int i = 0;
for (NSString *name in arnames)
{
obj_person *p = [[obj_person alloc] init];
p.personID = [arkeys objectAtIndex:i];
p.personName = name;
[mNsd setObject:p forKey:p.personID];
i++;
}
mCopy = [mNsd mutableCopy];
}
- (IBAction)btn_click:(id)sender
{
NSLog (#"%d original items", [mNsd count]);
obj_person *pp = [mCopy objectForKey:[NSNumber numberWithInt:mCounter]];
NSLog(#"%#", pp.personName);
pp.personName = #"Gerald";
if (++mCounter > [mCopy count])
mCounter = 1;
}
#end
Don't define:
NSMutableDictionary *mCopy;
NSMutableDictionary *mNsd;
Outside of the #interface and #implementation. They should be instance variables, so define instance variables or use properties to define them.
It's a good job you don't use n from:
for (NSArray *n in arnames)
because it isn't an NSArray, it's an NSString. You should fix that and you should probably both name it better than n and use it.
This:
obj_person *pp = [mCopy objectForKey:[NSNumber numberWithInt:1]];
fails because the key you originally stored with is an NSString instance and the thing you are using to try to get the data out is an NSNumber instance (so they can never match).
You might try:
mCopy = [mNsd mutableCopy];
[mCopy retain]
One theory is that the mutableCopy returns is an autoreleased object and it's being killed off before the btn_click function fires. According to this post: Retain/release of returned objects, mutableCopy should not be autoreleasing the array, but bugs do happen.
Else, maybe try iterating through with a for-loop instead.
int cnt = [arnames count];
for(int i=0; i<cnt; i++)
...

Creating Array with properties for each item in Objective-c

tell me please, how do I create an array in which each element will have a number of properties. For example:
array:
|
|-item 1 ( property_1-"Name1", property_2-"LastName1", property_3-"Age1");
|-item 2 ( property_1-"Name2", property_2-"LastName2", property_3-"Age2");
|-item 3 ( property_1-"Name3", property_2-"LastName1", property_3-"Age2");
|-…
In this case, the different elements of an array can have one and the same property, such as in the code posted above - "item 3" has the "property 2" is the same as in "item 1", and "property 3" is the same as in "item 2"
Tell me, please, how best to do it and, if not difficult, write a simple example or a link to some tutorial.
Thank you in advance)
There are two methods that I would suggest:
1. Use a class to store all the properties
Here's an example:
#interface Wrapper : NSObject
#property (nonatomic, assign) NSString* property_1;
#property (nonatomic, assign) NSString* property_2;
#property (nonatomic, assign) NSString* property_3;
#end
Then you can use it as a dictionary:
NSString* value=[myWrapperInstance valueForKey: #"property_1"];
But here comes the alternative solution:
1. Use a NSDictionary to store all the properties
NSDictionary* dict= #{ #"property_1" : #"Name1" ,#"property_2" : #"Name2", #"property_3" : #"Name3" };
Then the solution comes easy:
NSMutableArray* objects=[NSMutableArray new];
for(int i=0; i<N; i++)
{
NSDictionary* dict= #{ #"property_1" : #"Name1" ,#"property_2" : #"Name2", #"property_3" : #"Name3" };
[objects addObject: dict];
}
Sounds like you want an NSArray of NSDictionary objects:
NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:#"Name1", #"property_1", #"LastName1", #"property_2", #"Age1", #"property_3", nil);
NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:#"Name2", #"property_1", #"LastName2", #"property_2", #"Age2", #"property_3", nil);
NSDictionary *dict3 = [NSDictionary dictionaryWithObjectsAndKeys:#"Name3", #"property_1", #"LastName3", #"property_2", #"Age3", #"property_3", nil);
NSArray *array = [NSArray arrayWithObjects:dict1, dict2, dict3, nil];
If you want to update this later then you should use NSMutableDictionary and NSMutableArray, respectively.
If you are not using ARC, the you need to release objects when you are finished with them.

Write a complex array of custom structs to file Objective C

I need to save and load the contents of an array of structs, but I know that Objective C is very particular about which data types you can read/write with.
Here is my struct:
struct SCourse
{
NSMutableArray* holes; // holds integers (pars)
NSString* name;
int size;
BOOL inUse;
};
#interface CoursesManager : NSObject
{
struct SCourse courses[5];
}
What are the data types I'll need to use? Do they each have different methods needed in order to read/write? I'm just looking for a non-complex way to get all the data I need to and from a file. I could do this quite easily in a language I'm more familiar with (C++), but some of the particulars of Objective-c are still lost on me.
EDIT: Solution (thanks for the help, everyone)
-(void)applicationWillResignActive:(UIApplication *)application {
// save the courses
NSMutableArray* totalWriteArray = [[NSMutableArray alloc] initWithCapacity:MAX_COURSES];
for (int i = 0; i < MAX_COURSES; ++i)
{
struct SCourse saveCourse = [coursesManager GetCourseAtIndex:i];
NSNumber* nInUse = [NSNumber numberWithBool:saveCourse.inUse];
NSNumber* nSize = [NSNumber numberWithInt:saveCourse.size];
NSMutableArray* writeArray = [[NSMutableArray alloc] initWithCapacity:4];
[writeArray addObject:nInUse];
[writeArray addObject:nSize];
[writeArray addObject:saveCourse.name];
[writeArray addObject:saveCourse.holes];
[totalWriteArray addObject:writeArray];
}
[totalWriteArray writeToFile:[self saveFilePath] atomically:YES];
}
And for the loading back in...
-(void)loadFile {
NSString *myPath = [self saveFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSMutableArray* totalReadArray = [[NSMutableArray alloc] initWithContentsOfFile:[self saveFilePath]];
for (int i = 0; i < MAX_COURSES; ++i)
{
struct SCourse loadCourse = [coursesManager GetCourseAtIndex:i];
NSMutableArray* loadArray = [totalReadArray objectAtIndex:i];
NSNumber* nInUse = [loadArray objectAtIndex:0];
loadCourse.inUse = [nInUse boolValue];
NSNumber* nSize = [loadArray objectAtIndex:1];
loadCourse.size = [nSize integerValue];
NSString* inName = [loadArray objectAtIndex:2];
loadCourse.name = inName;
NSMutableArray* inHoles = [loadArray objectAtIndex:3];
loadCourse.holes = inHoles;
[coursesManager ReplaceCourseAtIndex:i With:loadCourse];
}
}
}
First thing first. You shouldn't use plain old C structures. The ARC memory management will not appreciate.
If you are familiar with C++, you should maybe use a C++ class instead, which will please the compiler and runtime. Depends on what you want to do.
Array. Use either NSArray or std::vector but please, no plain C arrays. Not sure how ARC will handle this but I suppose it will not appreciate much. Objective-C and C++ both provides all the tools you need to handle collections of whatever.
Serialization. You have several possibilities, one of them is NSCoder.
Last word, with the so called modern syntax, converting things into ObjC objects is quite easy.
BOOL b = YES;
int i = 10;
double d = 3.14;
char* s = "Pouf pouf";
You get the ObjC equivalents with the boxin' thingy:
NSNumber* bo = #( b );
NSNumber* io = #( i );
NSNumber* do = #( d );
NSString* so = #( s );
NSArray* ao = #[ #( i ), do ];
NSDictionary* = #{ #"num" : io, #"str" : #( s ) };
To write something in a file, in one gracious step:
[#{ #"bool" : bo, #"array" : #[ #"string", #10, #( 10 + 20 ) ] }
writeToFile: #"path.plist" atomically: YES];
But the question remains, what are you trying to accomplish?
One easy approach is to store these arrays in an NSMutableDictionary object and use the method:
[mutableDict writeToFile:#"path/to/file" atomically:YES];
To store the data and:
NSMutableDictionary *anotherDict = [NSMutableDictionary dictionaryWithContentsOfFile:#"path/to/file"];
To read the contents back in.
Here's what I'd suggest:
Make a custom class with the properties you want (.h file):
#import <Foundation/Foundation.h>
#interface CustomHolder : NSObject {
NSString *last;
NSString *first;
NSString *middle;
}
#property (strong, nonatomic) NSString *last;
#property (strong, nonatomic) NSString *first;
#property (strong, nonatomic) NSString *middle;
#end
And then set the .m file up so that you can encode/decode the object
#import "CustomHolder.h"
#implementation CustomHolder
#synthesize last, first, middle;
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:first forKey:#"first"];
[encoder encodeObject:last forKey:#"last"];
[encoder encodeObject:middle forKey:#"middle"];
}
- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [super init])
{
self.first = [decoder decodeObjectForKey:#"first"];
self.last = [decoder decodeObjectForKey:#"last"];
self.middle = [decoder decodeObjectForKey:#"middle"];
}
return self;
}
#end
Then you can just
[NSKeyedArchiver archiveRootObject:obj toFile:[self saveFilePath]] to save and
[NSKeyedUnarchiver unarchiveObjectWithFile:[self saveFilePath]] to load
That's probably the most similar to using C-structs (especially because ARC doesn't let you use structs).

objective-c multi-dimensional array

I want to use a variable-sized multi-dimensional array in my app to save data. The data structure I want to use is as below, the first element in each row is followed by corresponding multiple values.
array = { {a, a_val1, a_val2, a_val3}.
{b, b_val1},
{c, c_val1, c_val2, c_val3, c_val4, c_val5}
}
Any idea how I can implement in objective-c?
use NSMutableArray like so
NSMutableArray *curRow; /* use to access the row while loading with objects */
NSMutableArray *array = [[NSMutableArray alloc] init]; /* your main multidim array */
curRow = [NSMutableArray array];
[curRow addObject:/* what you want here */];
[curRow addObject:/* what you want here */];
[curRow addObject:/* what you want here */];
[array addObject:curRow]; /* first row is added */
/* rinse and repeat */
curRow = [NSMutableArray array];
[curRow addObject:/* what you want here */];
[curRow addObject:/* what you want here */];
[curRow addObject:/* what you want here */];
[array addObject:curRow];
use NSMutableArray
Below is the example for your understanding ...
NSMutableArray * multiArray = [[NSMutableArray alloc] initWithCapacity:5];
[multiArray addObject:[NSArray arrayWithObjects:a,a_val1,a_val2]];
[multiArray addObject:[NSArray arrayWithObjects:a,a_val1,a_val2,a_val3,a_val4]];
[multiArray addObject:[NSArray arrayWithObjects:a,a_val1,a_val5]];
[multiArray addObject:[NSArray arrayWithObjects:a,a_val1,a_val2,a_val3,a_val4,a_val5,a_val6]];
And Don't forget to release to multiArray array because we have alloced it ...
Objective-C does not have a real 2 dimensional array type but you can implement it with the
following codes..
in your header file --- yourheader.h
#import <Foundation/Foundation.h>
#interface yourheader : NSObject{
NSMutableDictionary* DictionaryArrayType;
NSMutableArray* MultiArrayType;
NSArray* CaptionTitle;
NSArray* ObjectValue;
}
#property (strong, nonatomic) NSMutableDictionary* DictionaryArrayType;
#property (strong, nonatomic) NSArray* CaptionTitle;
#property (strong, nonatomic) NSArray* ObjectValue;
#property (strong, nonatomic) NSMutableArray* MultiArrayType;
-(id) AddArrayObjects:(NSString*)_Name : (NSString*)_Surname :(NSString*)_Age;
-(id) AddArrayDictionaryObject:(NSArray*)_ArrayObject : (NSArray*)_ArrayKey;
-(id) AddMultiArrayType:(id)_ArrayObject;
-(void) ShowMultiArrayType:(id)_ArrayObject;
#end
Now add to your objective-c file ---- objective-c.m
#import "yourheader.h"
#implimentation yourheader
#synthesize DictionaryArrayType;
#synthesize CaptionTitle;
#synthesize ObjectValue;
#synthesize MultiArrayType;
-(id)init {
if(self = [super init]){
NSString* const NAME = #"NAME";
NSString* const SURNAME = #"SURNAME";
NSString* const AGE = #"AGE";
//Adding fixed content to CaptionTitle Array
[self setCaptionTitle:[NSArray arrayWithObjects:NAME, SURNAME, AGE, nil]];
//add values to ObjectValue array
[self AddArrayObjects:#"Bob" :#"Obi" :#"200"];
//add values to dictionary
[self AddDictionaryArrayType:ObjectValue :CaptionTitle];
//Add to the Multi dimensional array [][]
[self AddMultiArrayType:DictionaryArrayType];
//add the second row values to ObjectValue array
[self AddArrayObjects:#"Barack" :#"Obama" :#"50"];
//add values to dictionary
[self AddDictionaryArrayType:ObjectValue :CaptionTitle];
//Add to the Multi dimensional array [][]
[self AddMultiArrayType:DictionaryArrayType];
//display the 2d Array
[self ShowMultiArrayType:MultiArrayType];
}
return self;
}
-(id)AddArrayObjects:(NSString *)_name :(NSString *)_surname :(NSString *)_age {
//Set the Array Objects;
[self setObjectValue:[NSArray arrayWithObjects:_name, _surname, _age, nil]];
return self;
}
-(id)AddDictionaryArrayType:(NSArray *)_ArrayObject :(NSArray*)_ArrayKey {
if(!DictionaryArrayType) {
//initialize disctionary
[self setDictionaryArrayType:[NSMutableDictionary dictionary]];
}
//add array obeject and Fixed Key decleared in CaptionTitle array
DictionaryArrayType = [NSMutableDictionary dictionaryWithObjects:_ArrayObject forKeys:_ArrayKey];
return self;
}
-(id) AddMultiArrayType:(id)_ArrayObject {
if(!MultiArrayType) {
[self setMultiArrayType:[NSMutableArray array]];
}
[MultiArrayType addObject:_ArrayObject];
return self;
}
-(void)ShowMultiArrayType:_ArrayObject {
for(id objects in _ArrayObject ) {
for(id key in objects) {
NSLog(#"%# key = : object = %#", key, [objects objectForKey:key]);
}
}
}
#end;
To finish add this to your appdelegate.m file inside the app
yourclassname* _yourclasspointer = [[yourclassname alloc] init];
[_youclasspointer ShowMultiArrayType:[_yourclasspointer MultiArrayType]];
You should see it in you console.

Storing Sorted Arrays Causing EXC_BAD_ACCESS Error

Given a basic key/value array, I'm wanting to store two sorted arrays based on the original array: one array will be sorted by name, and the other by age.
The arrays seem to be sorting correctly when I output them to the log; however, when I try to access them elsewhere in the code, I'm receiving a EXC_BAD_ACCESS error.
Here's what I have so far:
// MyController.h
#interface MyController : UIViewController {
NSMutableArray *originalArray;
NSMutableArray *nameArray;
NSMutableArray *ageArray;
}
#property (nonatomic, retain) NSMutableArray *originalArray;
#property (nonatomic, retain) NSMutableArray *nameArray;
#property (nonatomic, retain) NSMutableArray *ageArray;
-(void)someRandomMethod;
#end
// MyController.m
#import "MyController.h"
#implementation MyController
#synthesize originalArray;
#synthesize nameArray;
#synthesize ageArray;
-(void)viewDidLoad {
// originalArray = (
// {
// "name" = "Sally";
// "age" = 18;
// },
// {
// "name" = "Chad";
// "age" = 26;
// },
// {
// "name" = "Carla";
// "age" = 24;
// },
// )
// sort by name
NSSortDescriptor *sortByNameDescriptor;
sortByNameDescriptor = [[[NSSortDescriptor alloc]
initWithKey:#"name"
ascending:NO] autorelease];
NSArray *sortByNameDescriptors = [NSArray arrayWithObject:sortByNameDescriptor];
nameArray = [originalArray sortedArrayUsingDescriptors:sortByNameDescriptors];
// sort by age
NSSortDescriptor *sortByAgeDescriptor;
sortByAgeDescriptor = [[[NSSortDescriptor alloc]
initWithKey:#"age"
ascending:NO] autorelease];
NSArray *sortAgeDescriptors = [NSArray arrayWithObject:sortByAgeDescriptor];
ageArray = [originalArray sortedArrayUsingDescriptors:sortByAgeDescriptors];
[super viewDidLoad];
}
-(void)someRandomMethod {
// whenever I try to access the sorted arrays, I receive the EXC_BAD_ACCESS error
[[nameArray objectAtIndex:0] valueForKey:#"name"];
[[ageArray objectAtIndex:0] valueForKey:#"age"];
}
-(void)viewDidUnload {
self.originalArray = nil;
self.nameArray = nil;
self.ageArray = nil;
[super viewDidUnload];
}
- (void)dealloc {
[originalArray release];
[nameArray release];
[ageArray release];
[super dealloc];
}
#end
Any ideas?
UPDATE: Thanks to #robin, by changing the code above to the code below, everything works great:
// sort by name
NSSortDescriptor *sortByNameDescriptor;
sortByNameDescriptor = [[[NSSortDescriptor alloc]
initWithKey:#"name"
ascending:NO] autorelease];
NSArray *sortByNameDescriptors = [NSArray arrayWithObject:sortByNameDescriptor];
nameArray = [[NSMutableArray alloc] initWithArray:[originalArray sortedArrayUsingDescriptors:sortByNameDescriptors]];
// sort by age
NSSortDescriptor *sortByAgeDescriptor;
sortByAgeDescriptor = [[[NSSortDescriptor alloc]
initWithKey:#"age"
ascending:NO] autorelease];
NSArray *sortAgeDescriptors = [NSArray arrayWithObject:sortByAgeDescriptor];
ageArray = [[NSMutableArray alloc] initWithArray:[originalArray sortedArrayUsingDescriptors:sortByAgeDescriptors]];
I dont think you know about this or not but when ever you create an object like string or array or dictionary, with init methods then the retain count gets incremented by 1
and if you create them like this
NSArray *anarray = [NSArray arrayWithArray:temp];
this will create an autorelease objects that will be released automatically after sometime.
So my advice don't use this type of code if you want to use the objects in more than 1 function. Always use init methods first to get the work done.
and if you are sure that the objects are not needed for the rest of the program than release them using release methode.