Quite a while back I wrote a post about storing and retrieving information using plists. This has turned out to be one of the most appreciated posts in my blog, both by the number of readers and the number of comments. My post also contained some errors, but friendly commenters have helped eachother out in order to resolve those errors.
When I wrote the original post I hadn't really resolved how to store information on a real device in the proper way. For example, if you have a file in your application bundle which you want to update, you should start by copying the file from the bundle to the Documents-directory.
To resolve the issues from the first post and show the "proper way" of handling files that are updated by the application I simply created a new Window-based Application and edited the "applicationDidFinishLaunching" method to look like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
[window makeKeyAndVisible];
// get the path to the "Documents" directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// get the path to our plist ("Documents/foo.plist")
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"foo.plist"];
// read or create plist
NSMutableDictionary *dict;
// check if our plist already exists in the Documents directory...
NSFileManager *fileManager = [NSFileManager defaultManager];
if ( [fileManager fileExistsAtPath:plistPath] ) {
// ...if it does, read it
NSLog(@"dict existed, reading %@", plistPath);
dict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
} else {
// ...if it doesn't, create it
NSLog(@"dict didn't exist, creating...");
dict = [NSMutableDictionary dictionaryWithCapacity:1];
// Fill the dictionary with default values, either by copying
// a default plist from our bundle to the Documents directory
// or simply creating a new dictionary and writing it to th
// Documents directory. Here we choose to create a new
// dictionary rather than providing a default plist in the bundle.
// create a NSNumber object containing the
// integer value 1 and add it as 'key1' to the dictionary.
NSNumber *number = [NSNumber numberWithInt:1];
[dict setObject:number forKey:@"key1"];
// write dictionary to Documents directory...
NSLog(@"writing to %@...", plistPath);
[dict writeToFile:plistPath atomically:YES];
}
// dump the contents of the dictionary to the console
NSLog(@"dumping...");
for (id key in dict) {
NSLog(@"key=%@, value=%@", key, [dict objectForKey:key]);
}
// check if key2 is present
NSString *value2 = (NSString *)[dict valueForKey:@"key2"];
if ( value2 == nil ) {
NSLog(@"key2 didn't exist, adding...");
[dict setObject:@"default-2" forKey:@"key2"];
}
// dump the contents of the dictionary to the console
NSLog(@"dumping...");
for (id key in dict) {
NSLog(@"key=%@, value=%@", key, [dict objectForKey:key]);
}
}
The code should be rather self-explanatory thanks to the inline comments, but I really recommend you to read my first post on this subject to really understand what is going on.
A thing worth commenting on is the really strange path names logged to the console. These pathnames can look like this:
2010-03-12 09:09:15.557 Plist2[10780:20b] writing to /Users/henrik/Library/Application Support/iPhone Simulator/User/Applications/E10D7186-1219-4C52-804A-FE217F760967/Documents/foo.plist...
This path is a path in the Mac OS filesystem used by the iPhone simulator when testing an application. The strange part of it is the long string of hexadecimal numbers starting with E10D7. This is the so called GUID which is unique for each installed application. A lot has been written about this in other sources on the Internet, so I won't go further into that:
One annoying thing about it and that is that it changes each time you recompile your application. That means, that each time you build and test your application the files created by the application will be somewhere else in the Mac OS filesystem. This makes it hard to inspect the files written by your application. Fortunately, modern versions of XCode copy the contents from the "old path" to the "new path" so even though the GUID changes, the files created by the application the last time are available the next time you build and test it.
If you couple this annoying thing with the fact that nothing is logged to the console if you exit your application by pressing the home-button in the simulator and then relaunch the application by pressing its icon in the simulator. This means that if you want to see what is logged to the console you are forced to relaunch the application from XCode, which will create a new GUID and thus a new path in the Mac OS filesystem.
However, since XCode nowadays copies the contents from the old to the new path it is possible to test how the application responds to "external changes" such as removing a file stored by the application, etc. This can be very convenient to perform effecient testing of an application.
For the application in this post you can test how it behaves if "foo.plist" is present or not by first running the application from XCode (CMD-Return), observing which path is logged to console, removing that file and then re-running the application from XCode (CMD-Return). This will give you something like this on the console:
[Session started at 2010-03-12 10:18:24 +0100.]
2010-03-12 10:18:27.456 Plist2[10888:20b] dict existed, reading /Users/henrik/Library/Application Support/iPhone Simulator/User/Applications/DB3B1A75-BF08-461E-919A-DBFFCC994036/Documents/foo.plist
2010-03-12 10:18:27.464 Plist2[10888:20b] dumping...
2010-03-12 10:18:27.468 Plist2[10888:20b] key=key1, value=1
2010-03-12 10:18:27.469 Plist2[10888:20b] key2 didn't exist, adding...
2010-03-12 10:18:27.471 Plist2[10888:20b] dumping...
2010-03-12 10:18:27.475 Plist2[10888:20b] key=key1, value=1
2010-03-12 10:18:27.477 Plist2[10888:20b] key=key2, value=default-2
[Session started at 2010-03-12 10:19:38 +0100.]
2010-03-12 10:19:40.159 Plist2[10897:20b] dict didn't exist, creating...
2010-03-12 10:19:40.180 Plist2[10897:20b] writing to /Users/henrik/Library/Application Support/iPhone Simulator/User/Applications/5B1E8FF3-45D6-443B-BB0B-2073EAE22520/Documents/foo.plist...
2010-03-12 10:19:40.191 Plist2[10897:20b] dumping...
2010-03-12 10:19:40.198 Plist2[10897:20b] key=key1, value=1
2010-03-12 10:19:40.199 Plist2[10897:20b] key2 didn't exist, adding...
2010-03-12 10:19:40.199 Plist2[10897:20b] dumping...
2010-03-12 10:19:40.200 Plist2[10897:20b] key=key1, value=1
2010-03-12 10:19:40.202 Plist2[10897:20b] key=key2, value=default-2
原來這世上能跟你共同領略一個笑話的人竟如此難得........................................
ReplyDeletehow do u do?
ReplyDelete裸體寫真全裸美女圖片色情訊息黃色圖片自拍裸體圖片sex裸露圖片18限85cc a片台灣色情網站免費色情圖一夜激情聊天情色聊天室限制級爆乳女優作愛巨乳學院性愛情慾陰脣一夜情下體網愛聊天鹹濕做愛自拍成人圖庫成人影城性關係視訊情人性影片觀賞裸照淫美成人論壇av寫真自拍裸女貼圖av圖情色性愛貼圖成人vcdsexy辣妹視訊聊天色情視訊淫婦台灣情色論壇丁字褲貼圖免費a片影片淫蕩女人live show男女做愛火辣妹妹激情網愛聊天美女裸照免費色情網站
ReplyDelete新浪視訊 色妹妹視訊高雄援交 34c視訊網愛聊天室 一對多視訊拓網辣妹視訊 176視訊聊天室 av最前線 視訊交友90739南台灣視訊 性愛貼圖 視訊聊天室90739 show-live視訊情色網 援交女豆豆出租情人視訊 sogo論壇視訊辣妹 桃園兼職援交辣妹視訊 一對一視訊520sex 日本視訊小魔女自拍 av1688影音娛樂網 辣手美眉甜心寶貝直播貼片 免費色咪咪視訊網pc交友 視訊美女ggoo 免費視訊情色網 咆哮小老鼠 高雄援交夢中情人情趣用品 sex888免費看影片波霸美女寫真 sex888免費看影片 視訊新竹援交留言 0401成人聊天室 甜心寶貝貼影片援交友留言桃園 sogo論壇080情人網 視訊泳裝秀拓網交友 色美眉免費看視訊 免費色咪咪影片網兼職援交 聊天室ilover99 a片天堂卡通aa片 台灣情色網無碼avdvd 色色網 sexydiamondsex888入口 高雄視訊辣妹自拍 免費a片亞洲東洋影片 hilive本土自拍天堂 西門慶成人論壇 費aaa片試看 dudusex免費影片 avdvd一夜情色妹妹免費情慾影片觀賞 qq美美色網影片av免費影片 日本a片自拍偷拍網站情色小說 jp成人a片 日本avdvd女優xxx383美女寫真
ReplyDelete我們唯一需要恐懼的事,是恐懼本身........................................
ReplyDelete很用心的blog,推推哦 ........................................
ReplyDeletehaha~ funny! thank you for your share~ ........................................
ReplyDeleteyour artical is so funny!! it make me so happy!! .............................................
ReplyDeleteGreat stuff - keep these coming, I find them very useful.
ReplyDeletexvideo打飛機專用網xvideos免費av影片A片洪爺免費85cc免費短片GOGO2聊天室77p2p免費短片洪爺色情片85cc A片go2 a片77p2p免費影片網洪爺貼圖區85cc線上看5278論壇77p2p線上看洪爺成人線上85cc免費看sogo色情77p2p免費看洪爺影城85cc影城go2影片77p2p影城洪爺色論壇85cc免費影片區go2免費影片77p2p免費影片區洪爺貼圖85cc影片區go2av影片77p2p影片區洪爺成年人網85cc成人片sogo成人77p2p成人片洪爺免費色情85cc觀看5278貼圖區77p2p觀看洪爺色情貼85cc影片5278影片網77p2p影片援交妹援交聊天室援交留言成人援交友辣妹野球拳辣妹露點
ReplyDelete免費成人影騙免費成人電影觀看曼雪兒情色文學成人小說杜雷斯成人貼圖區杜雷斯成人貼圖a片情色成人影片a片無碼圖片a片短片看a片電影城a片圖貼a片網路看a片影片免費看A片線上看a片免費線上影片a片免費影片線上a片免費影片網a片卡通火影忍者a片卡通直播a片孕婦做愛a片未成年a片在線看a片在線觀看a片成人免費觀賞a片免費下載無碼a片免費卡通a片免費成人影片a片免費免下載a片免費貼a片免費貼片a片論壇分享愛情禁忌視訊聊天交友mmshow交友104相親網成人圖片區
ReplyDeleteJudge not of men and things at first sight.............................................................
ReplyDelete量力而為,別勉強了,Cut your coat according to your cloth...................................................
ReplyDeleteHi Henrick!
ReplyDeleteThis is great. I have pieced this together from a variety of sources, but it is nice to see so well stated and all in one place.
I found this post because I am trying to solve a problem with my own PList implementation, and thought you might have some insight.
I have a high scores table in my PList, which is a Dictionary of Dictionaries like this:
HIGH SCORES
EASY
-> score
-> score
NORMAL
-> score
HARD
-> score
I want to allow users to clear the high scores. To do this I just flush the entire dictionary at each level (highScores setValue: forKey:@"EASY"). But that is where I get into trouble.
When I add new scores to the dictionary, the scores are getting saved as strings rather than numbers (which is how the implementation handles them).
I am setting values like this:
[scoresForDifficulty setValue:[NSNumber numberWithInt:numMoves] forKey:dateString];
So the value is of type NSNumber when it goes into the dictionary. But when I save the outermost dictionary with:
[settingsContent writeToFile:path atomically:YES];
Where settingsContent is the root of the PList, it stores the score values as Strings.
Am I doing something wrong, not doing something I should, or did I find an implementation issue in storing PLists in this way?
Cheers,
Chris
Hello Henrik. I have followed your previous and this post to do this task, but nothing works in my Xcode. Is there more codes I should write in order to make this Xcode project function? Perhaps something in .h file? Please answer asap, thank you. Mar
ReplyDelete