NSString to NSDictionary as object - ios

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];

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);

Converting NSString to NSArray and storing in NSUserdefaults

I have a string that downloads from a server. It is in JSON format and is well-formed. It is an array of JSON objects. My objective is to convert this to an NSArray and then store it in NSUserDefaults for subsequent use. My attempt generally works, but sometimes I crash with this error:
Attempt to set a non-property-list object
Here is the code that I am using. I think that it should be this straightforward. I don't believe have to actually convert the objects to NSDictionaries and iterate over this, do I?
NSString *message = [dict objectForKey:#"message"];
NSLog(#"message: %#", message);
data = [message dataUsingEncoding:NSUTF8StringEncoding];
NSArray *arr = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
[[NSUserDefaults standardUserDefaults] setObject:arr forKey:RESOURCES_LIST];
For example, this is one of the strings that causes this to crash (as output by the NSLog command):
[{"folder":"Documents","files":[{"sort_order":"120","filename":"pdf.pdf","filetype":"pdf","display_name":"Instructions","upload_date":"2015-08-11","md5":"ea9f839f91941b5ea7f5a316e3ce95ca","bool_external":"0","url":"http://www.somesite.com/pdf.pdf"}]},{"folder":"Images","files":[{"sort_order":"100","filename":"space.jpg","filetype":"image","display_name":"example","upload_date":"2015-10-14","md5":"bc63b896949cbf87c54678fee8ed833b","bool_external":"0","url":"http://www.somesite.com/space.jpg"},{"sort_order":"110","filename":"profile.png","filetype":"image","display_name":"Profile","upload_date":"2015-10-14","md5":"740d61911560e1c84869563b83f3bbf8","bool_external":"0","url":"http://www.somesite.com/profile.jpeg"}]},{"folder":"Info","files":[{"sort_order":"130","filename":"info.pdf","filetype":"pdf","display_name":"info","upload_date":"2015-11-17","md5":"926a7941cc9c7f58e43c3eb2de661c27","bool_external":"0","url":null}]},{"folder":"Videos","files":[{"sort_order":"130","filename":"sample_video","filetype":"video","display_name":"Instructional
Video","upload_date":"2015-08-11","md5":"-1","bool_external":"0","url":"https://www.youtube.com/embed/PuNIwSsz7PI"}]}]
"url": null
(in [2][#"files"][0])
This is likely being parsed into a value of [NSNull null], which cannot be stored in NSUserDefaults. You will need to either change the server to send as an empty string or not at all, or (recursively) iterate and check all values, removing (or replacing with #"") all keys with value [NSNull null].
For reference, the acceptable classes in plist files and NSUserDefaults are:
Array (NSArray)
Dictionary (NSDictionary)
String (NSString)
Data (NSData)
Date (NSDate)
Numerics [int32/64, float/double] (NSNumber)
Boolean (NSNumber)
And keys must be strings.

NSPropertyListSerialization returning nil instead of serialized data

I am putting two NSMutableArray objects into an NSDictionary and trying to serialize, but the method call is returning nil. One array, addresses, is an array of NSString objects. The other, engines is an array of objects that each contain several data types. I am attempting to serialize using the following code:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:engAddr forKey:#"engAddr"];
[dictionary setObject:trainList forKey:#"engines"];
NSData *data = [NSPropertyListSerialization dataFromPropertyList:dictionary
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
Stepping through, the debugger shows the arrays are properly added to the dictionary, but after the line that should serialize the dictionary it shows data = (NSData *) nil.
Where am I going wrong? Thank you for your help!
What kind of objects does engines contain?
Plist supports only specific objects below.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html#//apple_ref/doc/uid/10000048i-CH3-54303
If you want to serialize a custom object, convert it to NSData by NSKeyedArchiver.
To do that, objects must conform NSCoding protocol.

Which is the best way to save data (numbers) in a plist file

Initially I had an object made of three properties (numbers 0 to 12). NSCoder and related issues made me avoid using an object and now I store three NSNumbers directly instead. I save a NSMutableArray with the three values in this way
NSMutableArray *data=[[NSMutableArray alloc] initWithObjects: cardSign, cardNumber, cardColor, nil];
I save and check if data are saved
NSLog(#"wrote %hhd", [data writeToFile:path atomically:YES]);
I try to retrieve the data:
NSArray *dataRead = [[NSArray alloc] initWithContentsOfFile:path];
if (dataRead)
{
cardSign = [dataRead objectAtIndex:0];
cardNumber = [dataRead objectAtIndex:1];
cardColor = [dataRead objectAtIndex:2];
}
Before saving the variable values are correct.
When I try to retrieve the values I get all 0 or (null).
Which is the best way to store three numbers in a plist file and how do I retrieve it?
Most likely your objects "cardSign", "cardNumber", and "cardColor", are not actual objects. When storing array contents or NSArray contents to a file all objects must be Apple recognized objects, NSString, NSNumber, etc...
If for instance cardNumber is defined as follows:
int cardNumber;
Then when "data" is initialized if should be something like (pay only attention to cardNumber)
NSMutableArray *data=[[NSMutableArray alloc] initWithObjects: cardSign, [NSNumber numberWithInt:cardNumber], cardColor, nil];
This line is taken directly from discussion section of the Apple API description of the "initWithContentsOfFile" call.
"The array representation in the file identified by aPath must contain only property list objects (NSString, NSData, NSArray, or NSDictionary objects). The objects contained by this array are immutable, even if the array is mutable.

IOS and Objective C - How to display an NSMutableArray of NSDictionaries in NSUserDefaults in Tableview?

Basically I have an NSMutableArray of NSDictionaries stored to NSUserDefaults.
I have implemented tableview into my app but I am not sure how to display the individual values. I know that I am not providing much information (such as the keys I used) but could anyone give me a basic example on how access the values stored in NSDictionaries?
The code below doesn't work obviously, but if it were just a string it would be accessible in this way:
cell.textLabel.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"parked locations"];
If you stored mutable arrays in, you can access the NSMutableArray with the key #"parked locations" :
NSMutableArray *parkedLocations = [[NSUserDefaults standardUserDefaults]
objectForKey:#"parked locations"];
Each element of that array is a NSDictionary you access like that :
NSDictionary *parkedLocation = [parkedLocations objectAtIndex:0]; // the first
Finally inside each dictionary, access values like, for example NSString :
NSString *locationName = [parkedLocation objectForKey:#"theKeyForTheName"];
As NSUserDefaults can store objects of type : NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary, yes, if it were just a string, you could access it like you wrote.
You will find more information in Collections Programming Topics and User Defaults Programming Topics

Resources