26

So I have a plist structured string, that get dynamically (not from the file system). How would I convert this string to a NSDictionary.

I've tried converting it NSData and then to a NSDictionary with NSPropertyListSerialization, but it returns "[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x100539f40" when I attempt to access the NSDictionary, showing that my Dictionary was not successfully created.

Example of the NSString (that is the plist data):

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
 <key>Key1</key> 
 <dict> 
  <key>Test1</key> 
  <false/> 
  <key>Key2</key> 
  <string>Value2</string> 
  <key>Key3</key> 
  <string>value3</string> 
 </dict> 
</dict> 
</plist> 

Thanks!

christo16
  • 4,843
  • 5
  • 42
  • 53

3 Answers3

75

See Serializing a Property List

NSData* plistData = [source dataUsingEncoding:NSUTF8StringEncoding];
NSString *error;
NSPropertyListFormat format;
NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
NSLog( @"plist is %@", plist );
if(!plist){
    NSLog(@"Error: %@",error);
    [error release];
}
splicer
  • 5,344
  • 4
  • 42
  • 47
Peter N Lewis
  • 17,664
  • 2
  • 43
  • 56
  • 4
    +1 Your solution seems nicely polished — using immutable for creating an NSDictionary and remembering to release the error if there is one are worth bonus points. :-) – Quinn Taylor Jul 02 '09 at 04:45
  • I almost called that an over-release. Um, wow. That API totally violates the memory management rules by requiring the caller to release that error string. – Peter Hosey Jul 02 '09 at 05:17
  • According to the Release Notes, it changed to not have that violation in Leopard. Worth looking out for. There's a bug report about it: http://openradar.appspot.com/5563963 – Peter Hosey Jul 02 '09 at 07:20
  • My understanding is that the documentation is correct and the release notes are (now) wrong, as Apple decided to leave the leak in for compatibility reasons. – Michael Tsai Jul 02 '09 at 14:34
  • Michael Tsai: so you’re saying that my code that crashed on 10.5.0 when built against the Leopard SDK, because it was following the documented behaviour, will now leak on current versions of Leopard, unless I do a version check against an unspecified/undocumented version of the OS? [Citation needed] – Jens Ayton Jul 02 '09 at 20:50
  • The memory management rules only really talk about the return value, not asside values returned via reference like this, which, weirdly, do typically require releasing. – Peter N Lewis Jul 03 '09 at 02:34
  • Ahruman: I'm saying that your code will now leak, but you don't need to do a version check because only pre-release versions of 10.5 released the error string for you. Read the "NSPropertyListSerialization (Updated since WWDC 2007)" section of the updated release notes: http://developer.apple.com/releasenotes/Cocoa/Foundation.html – Michael Tsai Jul 04 '09 at 16:00
  • Hmm, that is interesting. I saw what appeared to be the changed behaviour in 10.5.0 final, and it went away when I stopped releasing the string. I wonder what my real bug was… – Jens Ayton Jul 04 '09 at 17:05
  • 19
    This method is now deprecated and you should use propertyListWithData:options:format:error: instead. – Rafael Bugajewski Apr 05 '11 at 18:29
  • please add swift version. – malhobayyeb Dec 07 '16 at 08:20
  • Sorry, I don't know a lick of Swift I'm afraid. If someone else wants to edit it to add a Swift variant, that's fine with me. – Peter N Lewis Dec 07 '16 at 13:08
13

Try this:

NSData * data = [yourString dataUsingEncoding:NSUTF8StringEncoding];

NSString *errorDesc = nil;
NSPropertyListFormat format;
NSDictionary * dict = (NSDictionary*)[NSPropertyListSerialization
                                      propertyListFromData:data
                                      mutabilityOption:NSPropertyListMutableContainersAndLeaves
                                      format:&format
                                      errorDescription:&errorDesc];
Marco Mustapic
  • 3,879
  • 1
  • 21
  • 20
  • Except for the memory leak, but heck it happens (: – Jay Sep 24 '09 at 09:45
  • NSDictionary * dict = (NSDictionary*)[NSPropertyListSerialization ...... You need to check the file you are trying to read as you may be returning an NSArray instead of NSDictionary. – Komposr Sep 26 '13 at 02:05
1

I've tried converting it NSData and then to a NSDictionary with NSPropertyListSerialization, but it returns "[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x100539f40" when I attempt to access the NSDictionary, showing that my Dictionary was not successfully created.

No, it shows no such thing. What it shows is that you tried to treat a string as an array. You'd need to determine where in the plist you were trying to get an array and why there was a string where you expected an array—i.e., whether you created the plist incorrectly (putting a string into it where you meant to put an array) or are examining it incorrectly (the presence of a string is correct; your subsequent expectation of an array is wrong).

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370