Here's a link to a screen-cast that I just finished uploading to vimeo.com. It details how to use NSKeyedArchivers and NSKeyedUnarchivers to load and save data. Although I use the iPhone SDK in the tutorial, the same principals can be used in your projects for the Mac OS as well.
It may still be converting, but it should be ready sometime on August 3. Also, the compression I used when recording the screen-cast did terrible things to the audio in a few parts. However, it doesn't obscure any of the info. I'm going to play around with the settings and see if I can iron out the kinks for the next tutorial I do.
Chris asked me to come back and embed the videos in these pages. But I didn't realize until I did it that the embedded versions weren't HiDef. However, you can click the link below the video to be taken to vimeo.com and you can view it in HiDef from there, or you can click the download link and download a HiDef version to your computer. All the videos except for the multiple-xib one are 75-ish meg in size.
Great tutorial. Awesome screen quality, sound is ok.. Hope your next tutorial will have better sound :P
That will come in handy very soon.
Thank you very much!
Yeah, I don't know if it was the compression or if it was the headset that I used. For my first tutorial, I used a USB microphone and recorded with no compression. Then I converted it to something else. For this tutorial, I recorded with compression to start out with, and I also changed to a bluetooth headset. I'm not sure which one caused the problem....it could be a combination of both.
I understand that, but you showed how to insert rows (which the my table reads from). So I was just curious how you could setup the data or array to allow for sections with rows inside.
I followed this tutorial all the way and ended up with about 90+ errors. I think I need to clear the app file and try it again. So much work, for such a simple function.
Quick question, I noticed you never released some of the temporary objects you used like the NSMutableData or the temp array when you were done with them, only the decoder. Was this on purpose, or just a quick and dirty tutorial? I'm still trying to wrap my head around when I should be releasing objects, autoreleasing, when things need to be retained or don't, and so on. I just finished my first app and it just hemorrhages memory like you wouldn't believe, so it's something I really need to learn.
the NSData and NSMutableData objects are autorelease variables, as is the temp array.
You'll have to forgive me, but why/how are they autorelease variables if you don't declare them as autorelease when you set them up? How do you know if something is an autorelease like those or is something that you'll need to release manually later? Will an error occur if you try to manually release an autorelease object?
Normally, anything that you don't specifically alloc and init are autorelease variables by default. I don't pretend to understand it fully, but after working with this stuff for a while I just kind of know when to specifically retain or release something.
Awesome tutorial! I've got my app, well, "sorta" working as a result. I'm using your code to set an in-app preference: a float value that controls the timing of some sound playback. (My app plays three sounds, and varies the timing between them based on a UISlider that sets the float value -- the preference.)
My app builds and runs okay on the simulator, and I can set the pref and read it back, and it does seem to actually affect sound playback as I want. So that's cool.
However, after I quit the app and run it again, it crashes out with errors ("*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFType floatValue]: unrecognized selector sent to instance 0x52d510'")
If I reset the simulator and build & go again, things are fine for one launch.
So I'm guessing that what I'm actually writing to the data file (the preference array) is somehow corrupt...thus when the app parses it back in from disk (as it does after a launch if the preference.dat file exists), something goes horribly wrong.
SO HERE'S MY QUESTION: do you know of a way to examine that preference.dat file on either the simulator or a provisioned device? (My preference.dat is the same thing as your person.dat file in your example.) I feel like if I could look at the contents of that file, I'd at least have a hint.
SO HERE'S MY QUESTION: do you know of a way to examine that preference.dat file on either the simulator or a provisioned device? (My preference.dat is the same thing as your person.dat file in your example.) I feel like if I could look at the contents of that file, I'd at least have a hint.
...Okay, and I managed to find the answer in another thread. These files live in the user's Library/Application Support/iPhone Simulator/User/Applications/UUID/Documents folder.
You can get the data file from the documents directory, but it isn't really human readable. From the looks of the error message, you're trying to do something with your float value that it can't do. Since the error message is happening when you launch the program, it sounds like you've got something wrong in either your load function or in your initWithCoder function.
My first question is do you get any warning when compiling? Something like "someInstanceVariable may not respond to selector ....."?
Okay, so your response was the key that helped me find the error, though it's hard for me to properly explain what I fixed, as it was a several-hour festival of fiddling, until suddenly all at once things seemed to work. Which is cool but not entirely confidence inspiring. Anyway, yes, I think part of the problem I had was that I was encoding an object into the archived/unarchived key (even though it was "just" a float, I was treating it as an object under the theory that someday I'd be encoding something other than a float).
Anyway, when I'd read that object back out and try to do stuff with it, I was inconsistent in my code -- sometimes I passed the object a 'floatValue' to cast it to a float, and sometimes I didn't. Depending on the context, sometimes this worked and sometimes it didn't. I had several warnings like you said, where the compiler was saying I was using potentially mismatching types (for example when I'd try to set up an NSNumber using the contents of the key and an initWithFloat). Because it halfway worked, I ignored those. Turns out they were actually a problem.
Ultimately what seems to have helped is simply being really consistent with the floatValue thing. For example, this works:
Code:
float n;
n = [[[mainDelegate.preferencesArray objectAtIndex:0] myPreference] floatValue];
Back to the fray.
(BTW, I now have a fully working app that launches, builds a default pref file if the pref file is not found on disk (or reads the pref file from disk), there's a UISlider to set the pref, and the pref is written to disk upon app exit. This is lightyears from where I was yesterday afternoon!)
If you're like me, you came to Objective-C from a C/C++ background, and all us C/C++ programmers know that any warnings while compiling a program usually mean absolutely nothing. That mindset is one that needs to be forgotten completely when working with Objective-C. 99 times out of 100 a compile-time warning in Objective-C means a run-time crash when that line of code is reached. Unless you know for sure that a warning can be ignored, you should stop the program and fix them immediately. Otherwise you're in for some headaches.