I'm adding items from one nsmutabledictionary to another nsmutabledictionary but the dictionaries are been add it as string values and not as dictionaries. Here is my code:
// mainDictionary contains dictionaries
NSMutableDictionary *result=[[NSMutableDictionary alloc]init];
for (id key in mainDictionary) {
[result addEntriesFromDictionary:[mainDictionary objectForKey:key]];
NSLog(#"type of class %#", NSStringFromClass([[result valueForKeyPath:#"key"] class]));
}
the output of NSLog is the following:
type of class __NSCFString
My question is how can add the dictionaries to the new dictionary keeping the integrity of the dictionaries ?
I'll really appreciate you help
Just try [result addEntriesFromDictionary:mainDictionary]; without the for loop. (Just in case mainDictionary is the desired dictionary that you want to add into the other dictionary
Related
I have an array inside a NSMutableDictionary and i want to add objects to it. With my current approach I get an error saying that the array is immutable.
I think the problem lies when I´m saving the dictionary to NSUserDefaults. I´m retrieving the is it a NSDictionary but I am at the same time creating a new NSMutableDictionary with the contents.
However, the array seems to be immutable. How do I replace an array inside of a dictionary?
My dictionary looks like this:
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:0], nil];
NSDictionary *dict = #{
#"firstKey": #{
#"theArray":array,
}
};
NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
I am trying to add objects like this:
[[[mutDict objectForKey:#"firstKey"] objectForKey:#"theArray"] addObject:[NSNumber numberWithInt:5]];
I am able to add objects to the array inside mutDict before its saved to NSUserDefaults
The error message I get when I try to add to the array inside the dictionary after loading it from NSUserDefaults:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
Here's what the documentation for dictionaryForKey: says on NSUserDefaults:
Special Considerations
The returned dictionary and its contents are immutable, even if the values you >originally set were mutable.
So when you retrieve your dictionary from NSUserDefaults the dictionary itself and all of the collections inside it are immutable. You can make the top level dictionary mutable (which I assume you are doing), but that won't propagate down into the now immutable NSArrays which are values in the dictionary.
The only way to get around this is to go through the dictionary that's returned and replace the immutable NSArrays with their mutable counterparts. It might look something like this.
- (NSMutableDictionary *)deepMutableCopyOfDictionary:(NSDictionary *)dictionary
{
NSMutableDictionary *mutableDictionary = [dictionary mutableCopy];
for (id key in [mutableDictionary allKeys]) {
id value = mutableDictionary[key];
if ([value isKindOfClass:[NSDictionary class]]) {
// If the value is a dictionary make it mutable and call recursively
mutableDictionary[key] = [self deepMutableCopyOfDictionary:dictionary[key]];
}
else if ([value isKindOfClass:[NSArray class]]) {
// If the value is an array, make it mutable
mutableDictionary[key] = [(NSArray *)value mutableCopy];
}
}
return mutableDictionary;
}
To be honest though it sounds like you're using NSUserDefaults for something a lot more complex then it is intended for. If you want to persist complex data structures then you should look into something like Core Data, or if that looks to be a bit overkill take a look at NSKeyedArchiver.
You can add object directly to the array:
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:0], nil];
NSDictionary *dict = #{
#"firstKey": #{
#"theArray":array,
}
};
NSMutableDictionary *mutDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
//Since Objective-C objects are always passed by reference (using pointers) you can add object to the array
[array addObject:[NSNumber numberWithInt:55]];
Swift example of adding object to array which is part of a dictionary.
let arr = [0] // note that initial array may be immutable
var dict = ["fK": ["a":arr]] // even if "arr" will be mutable, but "dict" immutable
dict["fK"]!["a"]!.append(3) // this will not work. "dict" must be mutable
println(dict) //[fK: [a: [0, 3]]]
Another approach
var arr = [0] // initial array must be mutable
var dict = ["fK": ["a":arr]] // in both cases dictionary must be mutable
arr.append(3)
let newArr = arr
dict["fK"]!["a"]! = newArr // because we change it's content
println(dict) //[fK: [a: [0, 3]]]
i'm trying to achieve the following structure:
NSMutableDictionary *dict = [#{} mutableCopy];
NSDictionary *key1 = #{#"id_format": #(1), #"date": #"2014-08-01"};
NSDictionary *key2 = #{#"id_format": #(2), #"date": #"2014-08-02"};
// This runs perfect and can be checked in llvm debugger
// data1 & data2 are NSArray that contain several NSDictionary
[dict setObject:data1 forKey:key1];
[dict setObject:data2 forKey:key2];
// Later, if i try to access dict using another key, returns empty NSArray
NSDictionary *testKey = #{#"id_format": #(1), #"date": #"2014-08-01"}; // Note it's equal to "key1"
for(NSDictionary *dictData in dict[testKey]){
// dictData is empty NSArray
}
// OR
for(NSDictionary *dictData in [dict objectForKey:testKey]){
// dictData is empty NSArray
}
So the question is if is there possible to use NSDictionary as key, or not.
An object can be used as a key if it conforms to NSCopying, and should implement hash and isEqual: to compare by value rather than by identity.
Dictionaries follow the array convention of returning [self count] for hash. So it's a pretty bad hash but it's technically valid. It means your outer dictionary will end up doing what is effectively a linear search but it'll work.
Dictionaries implement and correctly respond to isEqual:. They also implement NSCopying.
Therefore you can use a dictionary as a dictionary key.
In my application i am getting data from the server.i parsed the data and added to individual arrays. Here i am having 2 arrays.
For example
Array A : #"1",#"2",#"3",#"2",#"3",#"4",etc..
Array B : #"A",#"B",#"C",#"D",#"E",#"F",etc..
Now i want to create a Dictionary with Array A as keys and Array B as Values.
i am trying to create Dictionary like this:
dataDict = [NSDictionary dictionaryWithObjects:B forKeys:A];
But it is giving only single value for a single Key. here how can i store multiple values for a single key.
For Different keys its working. But my problem is Storing multiple values for single key.
You can't store multiple values for a single key directly -- dictionaries can only have one value per key. What you can do is store an array as the value. So, you could create a mutable dictionary and add the keys and values one at a time. Make the values all mutable arrays, and check for an existing value for the given key before setting it. If you find one, add the new value to the array.
Try this,
Assuming dataDict is a NSMutableDictionary and initialised.
- (void)addValueInDataDict:(id)value forKey:(NSString *)key {
if ([dataDict objectForKey:key] != nil) {
//Already exist a value for the key
id object = [dataDict objectForKey:key];
NSMutableArray *objectArray;
if ([object isKindOfClass:[NSMutableArray class]]) {
objectArray = (NSMutableArray *)object;
} else {
NSMutableArray *objectArray = [[NSMutableArray alloc] init];
}
[objectArray addObject:value];
[dataDict setObject:objectArray forKey:key];
} else {
//No value for the key
[dataDict setObject:value forKey:key];
}
}
I have an array structure as follows:
NSMutableArray topArray{
NSMutableArray middleArray{
NSMutableArray lowerArray{
NSMutableDictionary dict{
}
}
}
}
The array structure is filled with some data that I retrieve from the web is JSON format.
I am trying to edit one of the objects in the NSMutableDictionary as follow:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *lowerArray = [[self middleArray] objectAtIndex:[indexPath section]];
NSMutableDictionary *dict = [lowerArray objectAtIndex:[indexPath row]];
[dict setObject:[NSNumber numberWithInt:1] forKey:#"key"];
[[self tableView] reloadData];
}
The data within each of the arrays is correct (I have checked with print statements), however, when I try to change the object in the dict I get the following error:
reason:
'-[__NSCFDictionary setObject:forKey:]: mutating method sent to
immutable object'
I need the object in the dictionary to be changed within the array structure.
Could this be an issue with the JSON data since when topArray is first initialised with the JSON data the middle and lower arrays are in the form of just NSArray's?
Sorry if this is confusing, I will try to clarify more if you have any questions.
Thanks in advance for your help.
If you're using NSJSONSerialization, you can pass NSJSONReadingMutableContainers to the options parameter of +JSONObjectWithData:options:error:, and all of the parsed dictionaries and arrays will be mutable.
NSMutableArray *topArray = [NSJSONSerialization JSONObjectWithData:webServiceData
options:NSJSONReadingMutableContainers
error:nil];
Just use NSMutableDictionary class instead of just NSDictionary for the moduleDict variable. It is easily done when parsing JSON objects. If no - create one like this:
NSMutableDictionary *newDict = [NSMutableDictionary dictionaryWithDictionary: moduleDict];
I doubt that you are really dealing with NSMutableDictionary on the lowest level. Do you have the output from these print statements for us?
Usually the structures generated by JSON deserialisation are of immutable type. And that is exactly what your error message is telling.
I have a dictionary with key-value pair populated from JSON returned data.What I wish to do is use the dictionary to populate UITableView.
I have this structure for table:
[Product Name]
By [Manufacturer Name]
What this means is that key is Product Name and Value is Manufacturer Name. I need to get the name of the key and the name of the value. How can this be done? and is it possible without for-loop?
I'd use the enumerateKeysAndObjectsUsingBlock: method. The following code builds a list of the strings you require.
NSMutableArray *names = [NSMutableArray array];
[dictionary enumerateKeysAndObjectsUsingBlock: ^(NSString *key, NSString *object, BOOL *stop) {
[names addObject[NSString stringWithFormat:#"%# By %#",key, object]];
}];
You can use the keyEnumerator of NSDictionary and for each key look up the value. This could look something like this:
for (NSString *p in dict)
{
NSString *m = [dict objectForKey:p];
// do something with (p,m)
}
You should not be concerned with avoiding for-loops. After all, something like a for loop will always happen somewhere underneath.
If your keys are dynamic from json then you can use
NSArray *keys = [dictionary allkeys];
Then in the table View Cell for row at index path method you can populate the table view with the corresponding keys and their values.
NSArray * keys = [results allKeys];
for (int i = 0;i<[keys count];c++){
NSString* productName = [key objectAtIndex:i];
NSString* manufacturerName = [results objectForKey:productName];
}
Hope this helps...
I have assumed the name as strings, you can change the type according to your situation..