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.
Related
A NSDictionary in my code contains NSArrays with their respective keys (keys are float variables). When I tried to retrieve the NSArray using their respective keys, I get null value. I tried using both ObjectForKey and valueForKey methods, however the result is null.
'DictOfCoordinatesWrtDist' is a NSDictionary which contains 2-D coordinates(NSArray) as value and distance (NSNumber floatValue) as their respective keys. I want to retrieve those coordinates with their keys later in the code. While using objectForKey and valueForKey methods, the coordinates are null.
NSArray *AllDistsWrtBeacons = [DictOfCoordinatesWrtDist allKeys];
for( id dist in AllDistsWrtBeacons)
{ NSArray *beaconCoordinate = [DictOfCoordinatesWrtDist objectForKey:dist];
NSLog(#"X=%# Y=%#", [beaconCoordinate objectAtIndex:0],[beaconCoordinate objectAtIndex:1]);}
P.S: The NSDictionary 'DictOfCoordinatesWrtDist' contains beacons coordinate (Value) with respect to their distance (key). After executing this code, I get null value as coordinate.
You can't use direct float or integer,
As NSDictionarys are only designed to deal with objects, a simple way to do this is to wrap the integer and float in a NSNumber object.
For example,
NSArray *arr1 = [[NSArray alloc]initWithObjects:#"one",#"two", nil];
NSArray *arr2 = [[NSArray alloc]initWithObjects:#"red",#"green", nil];
NSNumber *key1 = [NSNumber numberWithFloat:1.1];
NSNumber *key2 = [NSNumber numberWithFloat:2.1];
NSDictionary *dict = [[NSDictionary alloc]initWithObjectsAndKeys:arr1,key1,arr2,key2, nil];
NSLog(#"%#",[dict objectForKey:key1]);
NSLog(#"%#",[dict objectForKey:key2]);
You can use below code.
NSArray *temp = #[#"1",#"2"];
NSDictionary *dic = #{
[NSNumber numberWithFloat:1.0] : temp,
#"Test1" : [NSNumber numberWithInt:22]
};
NSLog(#"Get dic with number = %#",[dic objectForKey:[NSNumber numberWithFloat:1.0]]);
[dict setObject:myArray forKey:[NSNumber numberWithFloat:1.0]];
You need convert your keys float to NSNumber or NSString like that:
NSDictionary *dict = #{
#(YOUR float Value) : #[Your array]
};
And I think more readable declare it using literals
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 have JSON data coming in using AFNetworking.
The responseObject holds an array of objects like so: [{"id":"XX", "description":"XX"}, {"id":"XX", "description":"XX"}]. This content is copied across to an NSArray, where by value access is obtained with objectAtIndex: valueForKey:.
I know object-c is overly complicated so I'm guessing that this is wishful thinking, but how would I go about creating a quick object to use in the event that responseObject is nil?
(any committed object-c coders, you'll have to excuse my bluntness. working with higher level languages causes logical ignorance)
if responseObject is nil
destinationArray= [{id:XX, description:XX}, {id:XX, description:XX}]
else
destinationArray = responseObject
You can do that with Objective-C literals:
if (!responseObject) {
destinationArray= #[
#{ #"id":#"XX",
#"description":#"XX"},
#{ #"id":#"XX",
#"description":#"XX"}
];
} else {
destinationArray = responseObject;
}
Where:
NSArray objects are #[ ... ].
NSDictionary objects are #{ ... }.
NSString objects are #"string".
NSNumber objects are #(1), #(1.2f), #(1.2), #(YES).
The data you are showing has 2 parts:
Multiple NSDictionaries, there are many ways to create them:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:...,nil];
Or you can define them by using its literal
NSDictionary *dictionary = #{#"id":#"XX", #"description":#"XX"};
An NSArray, to create an array you can use several options:
NSArray *array = [NSArray arrayWithObjects:...,nil];
Or, like before you can use the literal definition:
NSArray *array = #[dictionary1,dictionary2];
So, you can create the entire object like this:
if (responseObject == nil) {
destinationArray = #[#{#"id":#"XX", #"description":#"XX"},
#{#"id":#"XX", #"description":#"XX"}];
} else {
destinationArray = responseObject;
}
Read more at: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/FoundationTypesandCollections/FoundationTypesandCollections.html
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
I call an URL that returns me JSON (I use JSONKit). I convert it to a NSString that is this way:
[{"name":"aaaaaa","id":41},{"name":"as","id":23},...
And so on. I want to fill an UIPickerView with only the "name" part of the JSON. But, when the user selects a name, i need the "id" parameter, so i've thought to fill a NSDictionary with the JSON (setValue:id for key:name), so i can get the value picked by the user, and get the id from the dictionary. how could I fill an array with only the "name" of the JSON?
Im a bit lost with the JSONKit library, any guidance? Thank you.
First of all I don't think that its a good idea to have name as key in a dictionary, since you can have many identical names. I would go for id as key.
Now, what you could do is:
NSString *myJson; //Suppose that this is the json you have fetched from the url
id jsonObject = [myJson objectFromJSONString];
// Now you have an array of dictionaries
// each one having 2 key/value pairs (name/id)
NSArray *names = [jsonObject valueForKeyPath:#"name"];
NSArray *ids = [jsonObject valueForKeyPath:#"id"];
// Now you have two parallel arrays with names / ids
Or you could just iterate your json object and handle the data yourself:
for (id obj in jsonObject)
{
NSString *name = [obj valueForKey:#"name"];
NSNumber *id = [obj valueForKey:#"id"];
// Do whatever you like with these
}