NSDictionary objectForkey and accessing the key directly - ios

I have a simple question about accessing different ways of accessing values stored in NSDictionary. so if i have a dictionary like
NSDictionary *dict =#{#"Mammal" : #"Cow", #"Bird" : #"Eagle"};
Now what is the difference if i access the elements like dict[#"Mammal"] and [dict objectForKey:#"Mammal"] what if there is no object with key #"Mammal" in this case. Does it crash with dict[#"Mammal"] or dict[#"Mammal"] calls [dict objectForKey:#"Mammal"] under the hood.
Is it the similar case with NSArray, NSMutableArray & NSMutableDictionary

Using dict[#"Mammal"] actually calls - (id)objectForKeyedSubscript:(id)keyunder the hood.
The behaviour is the same as calling [dict objectForKey:#"Mammal"] according to the documentation:
Return Value
The value associated with aKey, or nil if no value is associated with aKey.
Discussion
This method behaves the same as objectForKey:.

Related

Adding object into NSMutableArray , crashing the App

Dict is coming from notification, taking out the NSData from dict and adding it to NSMutableArray is crashing the application.
Once in a while this crash is happening not always.
NSData *data=[dict objectForKey:#"obj"];
[self.RFTagData addObject:data];
You can directly add data object by doing this.Instead of converting to string.
Don't type cast NSData to NSString when adding objects into array.You should first convert NSData into NSString then add it to array.So
better way to use this NSData into NSString and add NSString into array.
NSData *data=[dict objectForKey:#"obj"];
NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if(data != nil self.RFTagData != nil)
{
[self.RFTagData addObject:strData];
.....
}
Example for Converting Data into String
You can directly get the data to array there is no need to cast.
if(self.RFTagData != nil){
self.RFTagData = [dict objectForKey:#"obj"];
}
NSLog(#"array %#", RFTagData);
This will add all data to array under the obj key.
Update:
As user rmaddy & danh suggested, so here needs to take concern over this point regarding use of valueForKey and objectForKey methods and nil check on the array.
objectForKey: This is an NSDictionary method. An NSDictionary is a collection class similar to an NSArray (collections), except instead of using indexes like NSArray, it uses keys to differentiate between items. A key is an arbitrary string you provide. No two objects can have the same key (just as no two objects in an NSArray can have the same index).
valueForKey: This is a KVC method. It works with ANY class. valueForKey: allows you to access a property using a string for its name.
Here both returns the value associated with a given key, so here using valueForKey method provides workaround solution to you. But using objectForKey is the more preferred way to use in such cases.
To check for the null values inside array which are identically appears like literals #"<null>" rather then NSNull objects typically used to represent nils in Cocoa collections. You can filter them out by using NSArray's filteredArrayUsingPredicate method:
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id value, NSDictionary *unused) {
return ![str isEqualToString:#"<null>"];
}];
NSArray *filteredAry = [self.RFTagData filteredArrayUsingPredicate:pred];
NSLog(#"array with non null vals %#", filteredAry);

NSMutableDictionary key value shuffled

I am facing very strange problem in NSMutableDictionary. Please see the below code.
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setValue:#"India" forKey:(#"Title")];
[dict setValue:#"Done" forKey:(#"Status")];
When I had printed this dictionary object, It shows like below.
{
Status =Done,
Title=India;
}
This keys getting shuffled, actually Title key should come first.
So, How can I resolve this issue.
That's not an issue.
You have mis understood or you'r getting wrong the NSDictionary. NSDictionary is a container to store values base on the keys.
So, there is no need of any order or indexing.
Reason behind is that you can only access container value if you know the key. So it is meaning less to check order of that keys. Because any how you have to use that key to access related value.
Now about order - Use NSArray instead and more of that use NSArray with object of NSDictionary. So that you have order with dictionary support.
Still the way to sort dictionary keys is below:
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setValue:#"India" forKey:(#"Title")];
[dict setValue:#"Done" forKey:(#"Status")];
NSArray *keys = [dict allKeys];
keys = [keys sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSLog(#"%#",keys);
NSDictionary or NSMutableDictionary does not guarantee any ordering of it's key/value pairs. There's no way to keep your keys/values in a set order and it doesn't make sense for NSDictionary or NSMutableDictionary to work like this. (You use keys not indexes to retrieve values).
If you want your values or keys in a certain order for display purposes you can sort them after retrieving them:
NSArray * sortedKeys = [ [ myDictionary allKeys ] sortedArrayUsingSelector:... ] ;
or
NSArray * sortedKeys = [ [ myDictionary allKeys ] sortedArrayUsingComparator:... ] ;
You could then retrieve the associated objects for the sorted keys if you wanted.
Another option is to maintain 2 separate arrays, one for keys and one for values and keep them in order.

NSString to NSDictionary as object

I have NSString representation of NSDictionary
I created the string like that:
NSString * insertionStr = [dictionary description];
Now I want to convert it back to NSDictionary
Is it possible ?
To save a dictionary to a file (or other medium) and be able to restore it later, you should use either JSON or the plist format.
For JSON your data must be limited to a combination of dictionaries, arrays, strings, and NSNumbers. For a plist it must be one of those or NSDate, or NSData.
For JSON you'd use the methods of NSJSONSerialization to convert to NSData, then save the data to a file. To restore, load the file into NSData and run back through NSJSONSerialization.
For plist format use the NSDictionary writeToFile and dictionaryWithContentsOfFile methods.
Do note that by default the objects you get back are immutable. If you want mutable objects from JSON there is an option on JSONObjectWithData called NSJSONReadingMutableContainers. With plists I believe you need to use the more complex plist interfaces (vs using the simple NSDictionary interfaces) that allow you to specify a similar option.
From the NSUserDefaults documentation for setObject:forKey
The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.
If your dictionary contains contains non-property list objects you can archive and store it to file if all objects in the dictionary implement NSCoding.
Based on the Question and comments i will say ...NO ...Don't do it like that.
NSUserDefaults has the capability to store object values and its perfectly fine to store NSDictionary
[[NSUserDefaults standardUserDefaults] setObject: dictionary forKey:#"DetailDict"];
[[NSUserDefaults standardUserDefaults] synchronize];
and retrive it use
NSDictionary *retrievedDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:#"DetailDict"];
OR
If you think you think of saving it as a string have a look at this question and when retrieving the value just convert back the string to Object
A dictionary is represented as key/value pairs. You can create a dictionary with a single value like this:
NSDictionary *dictionary = #{#"name": #"Mike"};
You can also store multiple key/value pairs:
NSDictionary *newDictionary = #{
#"firstName": #"Mike",
#"lastName": #"Smith"
};
Later if you want to get the value back out of the dictionary you use the key to get the value back out of it:
NSString *first = newDictionary[#"firstName"];
NSString *last = newDictionary[#"lastName"];
// first will now be #"Mike" and last will be #"Smith"
Think of a dictionary like an array, but instead of using indexes (numbers) to reference the value you use keys (strings).
Based on a comment made, if you also want to store an array of dictionaries you can do that no problem like this:
NSDictionary *firstDictionary = #{#"key": #"value"};
NSDictionary *secondDictionary = #{#"anotherKey": #"anotherValue"};
NSArray *array = #[firstDictionary, secondDictionary];

NSMutableArray addObject getting set to nil after release of object

I have declared an NSMutableArray *arrAllRecordsM and am trying to add NSMutableDictionary *dicRecordM to it using addObject. The dicRecordM gets added to arrAllRecordsM but on doing [dicRecordM removeAllObjects] it sets to nil in arrAllRecordsM. Below is the code, please help me fix it.
self.arrAllRecordsM = [NSMutableArray array];
self.dicRecordM = [NSMutableDictionary dictionary];
// Some Method
[self.dicRecordM setObject:#"Test" forKey:#"ADDRESS"];
[self.arrAllRecordsM addObject:self.dicRecordM];
// Value: Test
NSLog(#"Value: %#", [[self.arrAllRecordsM objectAtIndex:0] valueForKey:#"ADDRESS"]);
[self.dicRecordM removeAllObjects];
// Value: null
NSLog(#"Value: %#", [[self.arrAllRecordsM objectAtIndex:0] valueForKey:#"ADDRESS"]);
Adding an object to an NSMutableArray just stores a pointer (or "strong reference")
to the object into the array. Therefore
[self.arrAllRecordsM objectAtIndex:0]
and
self.dicRecordM
are two pointers to the same object. If your remove all key/value pairs from self.dicRecordM then [self.arrAllRecordsM objectAtIndex:0] still points to the same
(now empty) dictionary. That is the reason why
[[self.arrAllRecordsM objectAtIndex:0] valueForKey:#"ADDRESS"]
returns nil.
If you want an independent copy of the dictionary in the array, use
[self.arrAllRecordsM addObject:[self.dicRecordM copy]];
copy can be used on many classes, such as NSDictionary, NSArray and NSString
and their mutable variants, to get a "functionally independent object". Formally, it is available for all classes conforming to the NSCopying protocol.
This is expected behavior.
You removed all the objects from the dictionary by calling removeAllObjects, then tried to retrieve an object from it and rightfully getting nil, since it doesn't exist in the dictionay anymore (you removed it).
What's maybe unclear to you is that NSArray doesn't copy the element you add to it, instead it just holds a strong reference.
So both dicRecordM and arrAllRecordsM are holding a reference to the same object, hence any modification to it (in this case removeAllObjects) will affect the same dictionary.
Incidentally, you shouldn't use valueForKey: for accessing the dictionary's entries. Use objectForKey: or the shorter subscripted syntax. For instance
self.arrAllRecordsM[0][#"ADDRESS"]
You can read this answer Difference between objectForKey and valueForKey? as a reference, but the main problem is that valueForKey: can behave very differently from objectForKey: in case the key contains special KVC characters, such as # or ..

Get back value of Object key'ed NSMutableDictionary

I have a case where I need to have NSMutableDictionary with NSManagedObject as the key.
Based on this post, I can set NSManagedObject as key in dictionary by:
[NSValue valueWithNonretainedObject:]
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:product forKey:[NSValue valueWithNonretainedObject:category]];
How can I get back the value of dict? I've tried using NSValue again but it crash with no description.
Try using [theValue nonretainedObjectValue]
But if you want to access the keys frequently, a dictionary might not be the right data structure for you. Especially if you want some kind of inverse relationship with objects and keys (if that is what you mean with get back the value of dict).

Resources