Modifying content from new dictionary also modifies the parent dictionary data - iphone

As I have a requirement to add similar objects into the array, I have created new dictionary in such a way.
NSMutableDictionary* existingStepDict = [[[arrayForSteps objectAtIndex:0] mutableCopy] autorelease];
[arrayForSteps addObject:existingStepDict];
[existingStepDict release];
Now, what happens here is that later when I change something in any one of the dictionary, the other one also gets updated. I require both these dictionaries to behave independently.
For that I went through Deep-copy of dictionaries whose code is like this.
NSMutableDictionary* existingStepDict = [[[arrayForSteps objectAtIndex:0] mutableCopy] autorelease];
NSMutableDictionary* destination = [NSMutableDictionary dictionaryWithCapacity:0];
NSDictionary *deepCopy = [[NSDictionary alloc] initWithDictionary:existingStepDict copyItems: YES];
if (deepCopy) {
[destination addEntriesFromDictionary: deepCopy];
[deepCopy release];
}
//add Properties array to Steps Dictionary
[arrayForSteps addObject:destination];
But this too didn't reflect the difference. I know I am making some minor mistake here.
But could some one help me getting my result?
Thanks a lot!

There's an easy way to get a full deepcopy of an NSDictionary o NSArray using the NSCoding (serialization) protocol.
- (id) deepCopy:(id)mutableObject
{
NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject:mutableObject];
return [NSKeyedUnarchiver unarchiveObjectWithData: buffer];
}
In this way you can duplicate any object plus all the obects it contains in a single step.

when I need a mutable deep copy of a NSDictionary I create a Category with this method:
- (NSMutableDictionary *)mutableDeepCopy
{
NSMutableDictionary *returnDict = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for (id key in keys) {
id oneValue = [self valueForKey:key];
id oneCopy = nil;
if ([oneValue respondsToSelector:#selector(mutableDeepCopy)]) {
oneCopy = [oneValue mutableDeepCopy];
} else if ([oneValue respondsToSelector:#selector(mutableCopy)]) {
oneCopy = [oneValue mutableCopy];
}
if (oneCopy == nil) {
oneCopy = [oneValue copy];
}
[returnDict setValue:oneCopy forKey:key];
}
return returnDict;
}
EDIT
and searching the web I found this, I haven't tested
NSMutableDictionary *mutableCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);

Related

How to swap `NSMutableDictionary` key and values in place?

I have a NSMutableDictionary and I want to swap values & keys. i.e, after swapping values becomes keys and its corresponding keys with become values All keys and values are unique. Looking for an in place solution because size is very big . Also, the keys and values are NSString objects
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:#{
#"key1" : #"value1",
#"key2" : #"value2"}];
for (NSString *key in [d allKeys]) {
d[d[key]] = key;
[d removeObjectForKey:key];
}
NSLog(#"%#", d); // => { value1 : key1,
// value2 : key2 }
Assumptions
unique values (as they will become keys)
values conform to NSCopying (same as above)
no value is equal to any key (otherwise colliding names will be lost in the process)
Here is another way to invert dictionary. The simplest for me.
NSArray *keys = dictionary.allKeys;
NSArray *values = [dictionary objectsForKeys:keys notFoundMarker:[NSNull null]];
[dictionary removeAllObjects]; // In case of huge data sets release the contents.
NSDictionary *invertedDictionary = [NSDictionary dictionaryWithObjects:keys forKeys:values];
[dictionary setDictionary:invertedDictionary]; // In case you want to use the original dictionary.
EDIT: I had written a few lines of codes to get the OP started into the task of creating his own algorithm. The answer was not well received so I have crafted a full implementation of an algorithm that does what he asks, and goes one step further.
Advantages:
Makes no assumptions regarding the contents of the dictionary, for example, the values need not conform to the 'NSCopying' protocol
Transverses the whole hierarchy of a collection, swapping all the keys
It's fast since it uses recursion and fast enumeration
Does not alter the contents of the original dictionary, it creates a brand new one
Code has been implemented through categories to both collections:
#interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue;
#end
#interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue
{
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:self.count];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
id newKey = nil;
if ([value isKindOfClass:[NSDictionary class]]) {
newKey = [value dictionaryBySwappingKeyWithValue];
} else if ([value isKindOfClass:[NSArray class]]) {
newKey = [value arrayBySwappingKeyWithValue];
} else {
newKey = value;
}
if (![newKey conformsToProtocol:#protocol(NSCopying)]) {
newKey = [NSValue valueWithNonretainedObject:newKey];
}
mutableDictionary[newKey] = key;
}];
return [NSDictionary dictionaryWithDictionary:mutableDictionary];
}
#end
and...
#interface NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue;
#end
#implementation NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *newDict = [obj dictionaryBySwappingKeyWithValue];
mutableArray[idx] = newDict;
} else if ([obj isKindOfClass:[NSArray class]]) {
NSArray *newArray = [obj arrayBySwappingKeyWithValue];
mutableArray[idx] = newArray;
} else {
mutableArray[idx] = obj;
}
}];
return [NSArray arrayWithArray:mutableArray];
}
#end
As an example, assume you have a dictionary with the following structure:
UIView *view = [[UIView alloc] init];
NSDictionary *dict = #{#"1" : #"a",
#"2" : #[ #{ #"5" : #"b" } ],
#"3" : #{#"6" : #"c"},
#"7" : view};
NSDictionary *newDict = [dict dictionaryBySwappingKeyWithValue];
Printing the newDict object in the console will give you this output:
(lldb) po mutableDictionary
{
a = 1;
({b = 5;}) = 2;
{c = 6;} = 3;
"<30b50617>" = 7;
}
As you can see, not only have the keys and values been swapped at the first level of the hierarchy, but deep inside each collection.
"<30b50617>" represents the UIView object wrapped inside a NSValue. Since UIView does not comply to the NSCopying protocol, it needs to be handled this way if you want it to be a key in your collection.
Note: Code was done in a couple of minutes. Let me know if I missed something.
for (NSString *key in [myDictionary allKeys]) {
NSString *value = [responseDataDic objectForKey:key];
[myDictionary removeObjectForKey:key];
[myDictionary addObject:key forKey:value];
}
Assumption:
No key = value;
Complexity:
No extra space required. Will loop through once and replace all key value pairs.
NSArray* allKeys = [theDict allKeys];
NSArray* allValues = [theDict allValues];
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithObjects:allKeys forKeys:allValues];

NSArray with double entries

I have a NSArray with a lot of entries. But some of them are twice.
And i want that every entry is only once in the Array.
Have somebody an idea how i can do this?
This is how i've tried it:
NSSet *newsSet = [NSSet setWithArray:news];
newsOrte = [newsSet allObject];
In order to use NSSet effectively the object being stored must conform to the NSObject protocol and implement the hash (reference) and isEqual: (reference) methods.
Please ensure your object implements these methods.
Try this way
NSArray *array=[[NSMutableArray alloc]initWithObjects:#"A",#"B",#"A",#"C",#"A", nil];
NSMutableArray *arr=[NSMutableArray new];
for(id obj in array){
if (![arr containsObject:obj]) {
[arr addObject:obj];
}
}
array=arr;
NSLog(#"==> %#",array);
Also you can do in this way:
NSArray *array=[[NSMutableArray alloc]initWithObjects:#"A",#"B",#"A",#"C",#"A", nil];
NSMutableDictionary *dict=[[NSMutableDictionary alloc]initWithObjects:array forKeys:array];
array=[dict allKeys];
NSLog(#"==> %#",array);
Output :
==> (
A,
B,
C
)
Here is code
NSArray* originalArray = ... // However you fetch it
NSMutableSet* existingNames = [NSMutableSet set];
NSMutableArray* filteredArray = [NSMutableArray array];
for (id object in originalArray) {
if (![existingNames containsObject:[object name]]) {
[existingNames addObject:[object name]];
[filteredArray addObject:object];
}
}
originalArray = [NSArray arrayWithArray:filteredArray];
Hope it helps you..

Convert NSMutableArray to NSDictionary in order to use objectForKey?

I have an NSMutableArray that looks like this
{
"#active" = false;
"#name" = NAME1;
},
{
"#active" = false;
"#name" = NAME2;
}
Is there a way to convert this to an NSDictionary and then use objectForKey to get an array of the name objects? How else can I get these objects?
There is a even shorter form then this proposed by Hubert
NSArray *allNames = [array valueForKey:#"name"];
valueForKey: on NSArray returns a new array by sending valueForKey:givenKey to all it elements.
From the docs:
valueForKey:
Returns an array containing the results of invoking
valueForKey: using key on each of the array's objects.
- (id)valueForKey:(NSString *)key
Parameters
key The key to retrieve.
Return Value
The value of the retrieved key.
Discussion
The returned array contains NSNull elements for each object that returns nil.
Example:
NSArray *array = #[#{ #"active": #NO,#"name": #"Alice"},
#{ #"active": #NO,#"name": #"Bob"}];
NSLog(#"%#\n%#", array, [array valueForKey:#"name"]);
result:
(
{
active = 0;
name = Alice;
},
{
active = 0;
name = Bob;
}
)
(
Alice,
Bob
)
If you want to convert NSMutableArray to corresponding NSDictionary, just simply use mutableCopy
NSMutableArray *phone_list; //your Array
NSDictionary *dictionary = [[NSDictionary alloc] init];
dictionary = [phone_list mutableCopy];
This is an Array of Dictionary objects, so to get the values you would:
[[myArray objectAtIndex:0]valueForKey:#"name"]; //Replace index with the index you want and/or the key.
This is example one of the exmple get the emplyee list NSMutableArray and create NSMutableDictionary.......
NSMutableArray *emloyees = [[NSMutableArray alloc]initWithObjects:#"saman",#"Ruchira",#"Rukshan",#"ishan",#"Harsha",#"Ghihan",#"Lakmali",#"Dasuni", nil];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *word in emloyees) {
NSString *firstLetter = [[word substringToIndex:1] uppercaseString];
letterList = [dict objectForKey:firstLetter];
if (!letterList) {
letterList = [NSMutableArray array];
[dict setObject:letterList forKey:firstLetter];
}
[letterList addObject:word];
} NSLog(#"dic %#",dict);
yes you can
see this example:
NSDictionary *responseDictionary = [[request responseString] JSONValue];
NSMutableArray *dict = [responseDictionary objectForKey:#"data"];
NSDictionary *entry = [dict objectAtIndex:0];
NSString *num = [entry objectForKey:#"num"];
NSString *name = [entry objectForKey:#"name"];
NSString *score = [entry objectForKey:#"score"];
im sorry if i can't elaborate much because i am also working on something
but i hope that can help you. :)
No, guys.... the problem is that you are stepping on the KeyValue Mechanism in cocoa.
KeyValueCoding specifies that the #count symbol can be used in a keyPath....
myArray.#count
SOOOOOO.... just switch to the ObjectForKey and your ok!
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"theValue", #"#name", nil];
id kvoReturnedObject = [myDictionary valueForKey:#"#name"]; //WON'T WORK, the # symbol is special in the valueForKey
id dictionaryReturnedObject = [myDictionary objectForKey:#"#name"];
NSLog(#"object = %#", dictionaryReturnedObject);

can't acces key from NSDictionary

I have the following code:
- (id)initWithDictionaryRepresentation:(NSDictionary *)dictionary {
self = [super init];
if (self != nil) {
dictionaryRepresentation = [dictionary retain];
NSArray *allKeys = [dictionaryRepresentation allKeys];
NSDictionary *k = [dictionaryRepresentation objectForKey:[allKeys objectAtIndex:[allKeys count] - 1]];
NSArray *stepDics = [k objectForKey:#"Steps"];
numerOfSteps = [stepDics count];
steps = [[NSMutableArray alloc] initWithCapacity:numerOfSteps];
for (NSDictionary *stepDic in stepDics) {
[(NSMutableArray *)steps addObject:[UICGStep stepWithDictionaryRepresentation:stepDic]];
}
............
}
My app crashes at this line:
NSArray *stepDics = [k objectForKey:#"Steps"];
but also crashes if I try this : NSArray *stepDics = [k objectForKey:#"pr"];.It seems that I can't acces any of the keys!
This is how my dictionary looks like:
http://pastebin.com/w5HSLvvT
Any idea?
NSArray *allKeys = [dictionaryRepresentation allKeys];
Will return you the keys in an unpredictable order, so you shouldn't be using
id key = [allKeys objectAtIndex:[allKeys count] - 1]
as it could return something different every time, this is shown in the documentation for for this function in the NSDictionary Documentation.
The order of the elements in the array is not defined
Why dont you try
NSDictionary* a = [dictionary objectForKey:#"A"];
NSArray* stepDics = [a objectForKey:#"Steps"];
A dictionary will return nil if you ask for a key that doesn't exist. The fact that it's crashing means that you have a memory management error, not in the code you show above but in the code that creates the dictionary that is passed into your initWithDictionaryRepresentation: method. You're over-releasing the array that's stored in the #"Steps" key of the dictionary.

Weird bug while adding a NSDictionary to an NSArray

I got a really weird bug in my app today:
NSMutableDictionary *testLocal = [[NSMutableDictionary alloc] init];
[testLocal setObject:#"Test" forKey:#"title"];
[testLocal setObject:#"test notification" forKey:#"body"];
[testLocal setObject:#"1" forKey:#"repeat"];
[testLocal setObject:#"26.04.2011 - 12:53" forKey:#"start"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[saver read]];
[[dict objectForKey:#"content"] addObject:testLocal]; //Crashes here! (SIGABRT)
The method [saver read] returns this:
{
content = (
{
body = "test notification";
repeat = 1;
start = "26.04.2011 - 13.06";
title = Test;
}
);
}
So I don't see the error because the dict I write to is mutable and the key "content" is an array.
Thanks in advance.
mavrick3.
[saver read]:
- (NSDictionary *)read {
return [[NSDictionary alloc] initWithContentsOfFile:[self filePath]];
}
Try checking out what class the object returned by [dict objectForKey:#"content"] is. Then things will be much clearer to you. I suspect it is not returning an NSMutableArray instance but something else, most likely NSArray which doesn't respond to method addObject:
From apple Documentation for objectForKey :
The value associated with aKey, or nil if no value is associated with aKey.
So your code could be like below
if([dict objectForKey:#"content"] != nil && [[dict objectForKey:#"content"] isKindOfClass:[NSMutableArray class]] )
{
[[dict objectForKey:#"content"] addObject:testLocal];
}
else
{
[dict setObject: textLocal forKey: #"content"];
}
Is the array to which you want to add a dictionary mutable?