Add values in NSMutableDictionary in iOS with Objective-C - ios

I'm starting objective-c development and I would like to ask the best way to implement a list of keys and values.
In Delphi there is the class TDictionary and I use it like this:
myDictionary : TDictionary<string, Integer>;
bool found = myDictionary.TryGetValue(myWord, currentValue);
if (found)
{
myDictionary.AddOrSetValue(myWord, currentValue+1);
}
else
{
myDictionary.Add(myWord,1);
}
How can I do it in objective-c? Is there equivalent functions to the above mentioned AddOrSetValue() or TryGetValue()?
Thank you.

You'd want to implement your example along these lines:
EDIT:
//NSMutableDictionary myDictionary = [[NSMutableDictionary alloc] init];
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
NSNumber *value = [myDictionary objectForKey:myWord];
if (value)
{
NSNumber *nextValue = [NSNumber numberWithInt:[value intValue] + 1];
[myDictionary setObject:nextValue forKey:myWord];
}
else
{
[myDictionary setObject:[NSNumber numberWithInt:1] forKey:myWord]
}
(Note: you can't store ints or other primitives directly in a NSMutableDictionary, hence the need to wrap them in an NSNumber object, and make sure you call [myDictionary release] when you've finished with the dictionary).

The other answers are correct, but there is more modern syntax for this now. Rather than:
[myDictionary setObject:nextValue forKey:myWord];
You can simply say:
myDictionary[myWord] = nextValue;
Similarly, to get a value, you can use myDictionary[key] to get the value (or nil).

Yep:
- (id)objectForKey:(id)key;
- (void)setObject:(id)object forKey:(id)key;
setObject:forKey: overwrites any existing object with the same key; objectForKey: returns nil if the object doesn't exist.
Edit:
Example:
- (void)doStuff {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"Foo" forKey:#"Key_1"]; // adds #"Foo"
[dict setObject:#"Bar" forKey:#"Key_2"]; // adds #"Bar"
[dict setObject:#"Qux" forKey:#"Key_2"]; // overwrites #"Bar"!
NSString *aString = [dict objectForKey:#"Key_1"]; // #"Foo"
NSString *anotherString = [dict objectForKey:#"Key_2"]; // #"Qux"
NSString *yas = [dict objectForKey:#"Key_3"]; // nil
}
Reedit: For the specific example there exists a more compact approach:
[dict
setObject:
[NSNumber numberWithInteger:([[dict objectForKey:#"key"] integerValue] + 1)]
forKey:
#"key"
];
Crazy indentation for readability.

Related

how to get nsDictionary element by using for-in

NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
for (NSDictionary* tmp in myDict) {
NSLog(#"%#",tmp);
}
resut:
my tmpis NSString
I want to get a dictionary with key= one , value = 1
for in for NSDictionary will iterate the keys.
for (NSString * key in myDict) {
NSLog(#"%#",key);
NSString * value = [myDict objectForKey:key];
}
If you want to get a dictionary. You have to create a dictionary from these values
for (NSString * key in myDict) {
NSLog(#"%#",key);
NSString * value = [myDict objectForKey:key];
NSDictionary * dict = #{key:value};
}
Or you should init like this:
NSArray *arrDict = #[{#{"one":#"1"},#{#"two":#"2"}];
for (NSDictionary* tmp in arrDict) {
NSLog(#"%#",tmp);
}
You can get all keys from your dic then add the key and value to your new dic like this:
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
NSArray *keys = [myDict allKeys];
for (NSString *key in keys) {
NSDictionary *yourDic = #{key: [myDict valueForKey:key]};
NSLog(#"%#", yourDic);
}
You didn't create it that way. If you wanted to have a NSDictionary inside another NSDictionary you should write something like this :
NSDictionary *myDict = #{
#"firstDict" : #{
#"one":#"1"
},
#"secondDict": #{
#"two":#"2"
}
};
Above code will create a NSDictionary with two dictionaries at keys #firstDict and #secondDict.
Also, bear in mind, that because dictionaries are key-value pairs, using a for-in loop, actually loops through the keys in that dictionary. So your code is equivalent to:
for(NSString *key in dict.allKeys) { ... }
I got the solution
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
NSMutableArray *arrayObject = [[NSMutableArray alloc]init];
NSMutableArray *arrayKey = [[NSMutableArray alloc]init];
NSMutableArray *arrayObjectKey = [[NSMutableArray alloc]init];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
for (NSString *stringValue in myDict.allValues)
{
[arrayObject addObject:stringValue];
}
for (NSString *stringKey in myDict.allKeys)
{
[arrayKey addObject:stringKey];
}
for(int i = 0;i<[arrayKey count];i++)
{
dict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:[NSString stringWithFormat:#"%#",[arrayKey objectAtIndex:i]],#"key",nil];
[dict setObject:[NSString stringWithFormat:#"%#",[arrayObject objectAtIndex:i]] forKey:#"value"];
[arrayObjectKey addObject:dict];
}
NSLog(#"The arrayObjectKey is - %#",arrayObjectKey);
The Output is
The arrayObjectKey is -
(
{
key = one;
value = 1;
},
{
key = two;
value = 2;
}
)
Create the dictionary:
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys:#"1",#"One",#"2","Two",nil];
Get a value out using:(this example tmp will be 1)
NSString *tmp = [myDict objectForKey:#"One"];
Display the output in console:
NSLog(#"%#",tmp);
To display the whole NSDictionary
NSLog (#"contents of myDict: %#",myDict);
What you are doing is creating a dictionary with key-value pairs. I think what you want to do is have an array with dictionaries.
NSArray *myArray = #[#{#"one":#"1"}, #{#"two":#"2"}];
for (NSDictionary* tmp in myArray) {
NSLog(#"%#",tmp);
}
However I don't see a point in doing this. What you could do is:
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
for (NSString* key in [myDict allKeys]) {
NSLog(#"%# = %#", key, myDict[key]);
}

xcode - set value of a nested object

I have a json from a service and I need to change the values of one obeject.
{
question = (
{
answer = (
{
Id = 1;
value = 1;
},
{
Id = 2;
value = 0;
}
);
},
.....
I use that code to directly access to the second "value" element and set it to "true"
NSMutableDictionary * dict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
NSMutableDictionary *preguntasDict = [[NSMutableDictionary alloc] init];
preguntasDict =[[[dict valueForKey:#"question"]mutableCopy];
NSMutableDictionary *answer = [[NSMutableDictionary alloc] init];
respuestasDict =[[[[preguntasDict valueForKey:#"answer"]objectAtIndex:0]objectAtIndex:1] mutableCopy];
[respuestasDict setObject:[NSNumber numberWithBool:true] forKey:#"value"];
It works: "respuestasDict" changes but the whoole "dict" not.
My question is: how could rebuild the entire dictionary? or it is possible to access directly to the nested object and change it?
Note that perguntasDict and respuestasDict are mutable copies of your dictionaries, so basically you are editing copies of your dict. You need to access dict directly, like this:
NSArray *answers = dict[#"question"][#"answer"];
[answers firstObject][#"value"] = #(YES);
PS: Doing dict[#"question"] is the same thing as [dict objectForKey:#"question"]. Also, #(YES) is the same thing as [NSNumber numberWithBool:true]

Using NSPredicate to filter an object and a key(that needs to be split)

I have the following dictionary set up(Object, Key)
0, "10;0.75,0.75"
1, "0;2.25,2.25"
3, "1;3.5,2.0"
4, "1;4.5,3.0"
5, "2;6.0,5,0"
What I want to filter will be based on the object AND the key. The object is a NSNumber. The key is a string but i really don't want the entire string. I want to split the string separated by the semicolon and take the first index of the split which would yield the strings 10,0,1,1 or 2 depending on which object I was looking for.
As a specific example:
Are there any keys that are equal to #"1" with an object that is greater than 3.
In this case i should expect back YES since object 4 has a key that is equal to #"1", after i do the split.
I guess I was looking for a clever way to define a NSPredicate to do the split on the key separated by the semicolon and then filter(compare, etc) based on that. Let me know if you have any questions or need additional info.
A very naive implementation that I could think of
- (BOOL)hasKey:(NSString *)key withValueGreaterThan:(id)object{
NSDictionary *dictionary = #{#"10;0.75,0.75": #0,
#"0;2.25,2.25" : #1,
#"1;3.5,2.0" : #3,
#"1;4.5,3.0" : #4,
#"2;6.0,5,0" : #5};
NSPredicate *keyPredicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH %#",key];
NSArray *filteredKeys = [[dictionary allKeys]filteredArrayUsingPredicate:keyPredicate];
for (NSString *k in filteredKeys) {
NSNumber *value = dictionary[k];
if (value>object) {
return YES;
}
}
return NO;
}
Use
BOOL hasValue = [self hasKey:#"1;" withValueGreaterThan:#3];
Sample Code:
NSDictionary* dict = #{ #"10;0.75,0.75":#0,
#"0;2.25,2.25":#1,
#"1;3.5,2.0":#3,
#"1;4.5,3.0":#4,
#"2;6.0,5,0":#5};
__block NSString* foundKey = nil;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSNumber* obj, BOOL *stop) {
//here goes condition
//get substr
NSArray* arr = [key componentsSeparatedByString:#";"];
int num = [[arr objectAtIndex:0]integerValue];
if ((num == 1)&&([obj integerValue]>3)) {
foundKey = key;
stop = YES;
}
}];
if (foundKey) {
NSLog(#"%#:%#",foundKey,[dict objectForKey:foundKey]);
}
Just use the following method:
-(BOOL)filterFromDictionary:(NSDictionary*)dict keyEqual:(NSString*)key greaterthanObj:(NSString*)obj
{
NSArray *allKeys = [dict allKeys];
for (NSString *eachkey in allKeys) {
NSString *trimmedKey = [self trimKeyuntill:#";" fromString:eachkey];
NSString *trimmedValue = [dict objectForKey:eachkey];
if ([trimmedKey isEqualToString:key] && [trimmedValue intValue] > [obj intValue]) {
return YES;
}
}
return NO;
}
call the above method with your dictionary like:
NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"1",#"1",#"3",#"4",#"5", nil] forKeys:[NSArray arrayWithObjects:#"10;0.75,0.75",#"0;2.25,2.25",#"1;3.5,2.0",#"1;4.5,3.0",#"2;6.0,5,0", nil]];
[self filterFromDictionary:dict keyEqual:#"1" greaterthanObj:#"3"]
I assumed all your objects are nsstrings. otherwise change the intValue

IF statement issue in IOS using NSString

My if statement won't work. active returns 1 but will not work in the IF statement
JSONDecoder *jsonKitDecoder = [JSONDecoder decoder];
NSDictionary *dict = [jsonKitDecoder objectWithData:jsonData];
NSString *userid = [dict valueForKeyPath:#"users.user_id"];
NSString *active = [dict valueForKeyPath:#"users.active"];
NSLog(#"%#",userid); // 2013-06-20 03:03:21.864 test[81783:c07] (74)
NSLog(#"%#",active); // 2013-06-20 03:03:21.864 test[81783:c07] (1)
if ([active isEqualToString:#"1"]){
// Do something
}
I can't seem to get this IF to work. Do I need to change the NSString to a int?
For starters, use a modern style for retrieving values from dictionaries, rather than valueForKeyPath:.
NSDictionary* users = dict[#"users"];
id active = users[#"active"];
Once you're using a modern style, my guess is that the active value is actually an NSNumber representing a boolean value. So your if block would read:
if([active isKindOfClass:NSNumber] && [active boolValue]) {
//active is an NSNumber, and the user is active
}
The syntax of your if statement is just fine. I would try the alternate method for retrieving values from a dictionary as mentioned above.
NSString *active = #"1";
if ([active isEqualToString:#"1"])
{
// Do something
NSLog(#"It works!");
}
More than likely the "users.active" object being returned from that NSDictionary-ized JSON stream is a "BOOL" or a "NSInteger" as the payload of a NSNumber object and it's not a NSString object.
Try using:
NSNumber * activeNumber = [dict valueForKeyPath: #"users.active"];
and see if "if ([activeNumber boolValue] == YES)" works better for you.

Accessing NSMutableDictionary inside NSMutableArray

I have an NSMutableArray of NSMutableDictionary (it's a plist). Each dictionary in the array has 2 keys: 'id' and 'lu'.
How can I find the index in NSMutableArray of NSMutableDictionary where, for example, id = '47653'?
I tried to do it but it's not working:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *path = [basePath stringByAppendingPathComponent:#"id.plist"];
NSMutableArray *mut_array = [[NSArray arrayWithContentsOfFile:path] mutableCopy];
NSMutableDictionary *mut_dico = [[NSMutableDictionary alloc] init];
NSString *egalIDPlistData = [contentDictio objectForKey:#"id"];
for(mut_dico in mut_array) {
if([[mut_dico objectForKey:#"id"] isEqualToString:#"47653"]) {
NSLog(#"Test");
}
}
NSMutableArray *mut_array = [[NSArray arrayWithContentsOfFile:path] mutableCopy]; will create a mutable array of immutable dictionaries, not mutable dictionaries. mutableCopy is not a deep copy.
Regardless of mutability, the following will do what you want:
NSUInteger indexOfDictionary = [[array valueForKey:#"id"] indexOfObject:#"49711"];
if(indexOfDictionary == NSNotFound)
{
NSLog(#"no matching objects found!");
return;
}
NSDictionary *fullDictionary = [array objectAtIndex:indexOfObject];
The valueForKey: uses the fact that a key-value coding call on an array returns an array of the results of that call on each object in the array, in the same order, and the fact that NSDictionary will respond similarly in this situation to both valueForKey: and objectForKey:
As for the issue of whether what you're really dealing with is strings or numbers, try using just #49711 in place of #"49711" and if that works instead you've got numbers.
In your log id is 49711 & in your if condition it is 47653. Your condition will not satisfy until there is dictionary in your array with id = 47653
The objects in the loaded plist are not mutable.
Try:
for(NSDictionary * dict in mut_array)
{
if([[dict objectForKey:#"id"] isEqualToString:#"49711"]) {
NSLog(#"Test");
}
}

Resources