views:

3813

answers:

2

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"&gt; 
<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!

+5  A: 

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
Perfect! Thanks!
christo16
Except for the memory leak, but heck it happens (:
Jacob
+13  A: 

See Serializing a Property List

NSData* plistData = [source dataUsingEncoding:NSUTF8StringEncoding];
NSString *error;
NSPropertyListFormat format;
NSDictionary* plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
NSLog( @"plist is %@", plist );
if(!plist){
 NSLog(@"Error: %@",error);
 [error release];
}
Peter N Lewis
+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
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
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
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
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]
Ahruman
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
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
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…
Ahruman