I have grown very fond of using NSDictionary and NSMutableDictionary if I want to put diverse data into a single object to pass around in my programs. Also NSDictionary has the built-in capability of saving and reading itself to disk, in the so-called property list (abbreviated as “plist”) format.
Now I was implementing caching of such a NSDictionary in my app and for mysterious reasons the following code would not result in any file being saved:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *path = [documentsDirectory stringByAppendingPathComponent:@"notworking.plist"]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; NSNumber *numKey = [NSNumber numberWithInt:123]; [dict setObject:@"a Value" forKey:numKey]; // legal: using a NSNumber as key [dict writeToFile:path atomically:YES]; [dict release]; |
Can you spot the problem? Probably not, if you check the documentation you will read that NSDictionary can hold and save any of the following data types: NSNumber, NSData, NSString, NSDictionary, NSArray. I did not use anything else, therefore the dictionary should be saved as a plist. With lots of experimenting however I found a simple change to the above code that makes it work:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *path = [documentsDirectory stringByAppendingPathComponent:@"working.plist"]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; NSString *stringKey = @"123"; [dict setObject:@"a Value" forKey:stringKey]; // workaround [dict writeToFile:path atomically:YES]; [dict release]; |
Simply put you cannot use anything except as a string as the root key of an NSDictionary. The above code will save an XML file looking like this:
<?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>123</key> <string>a Value</string> </dict> </plist> |
If you want to save a dictionary, make sure you use only strings for keys. In another case I was using an NSDate as valid key for an entry in a dictionary. Same result: writing it to a file does not work. Why there is such a limitation I cannot say. In any case I submitted it as bug report to Apple.
Having pondered this a little I realized the most probable explanation. If you look at the way an XML plist is represented in the file you can see that there is no indication as to what data type the <key> represents. Therefore it can only be a string.
Categories: Recipes