Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Jul 12, 2009, 03:11 PM   #1
mdeh
macrumors 6502
 
Join Date: Jan 2009
NSCoder issue/clarification

May I ask the advice of the experts here?

I have successfully added archiving to a non-doc based Application. (Yes...I am going through Hillegass, with a twist!

1) Adopted NSCoding in the model class

2) Call archiveRootObject like this.

Code:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
    {
	....preparatory stuff
	
	[NSKeyedArchiver archiveRootObject: self toFile: savedValuesFile];


	...more stuff }
3) call unarchiveObjectWithFile like this.

Code:
-(id) init
{
	
	....preparatory stuff
	
		return [NSKeyedUnarchiver unarchiveObjectWithFile:savedValuesFile];


	}
Here is what puzzles me.

Both
Quote:
-(id) initWithCoder: (NSCoder *) coder
and
Quote:
-(void) encodeWithCoder: (NSCoder *) coder
are clearly called with the correct "coder" argument. I just wonder **how** these two methods receive the **correct** instance of coder. Particularly puzzling is the call in "init" which does not even handle the returned object, yet it obviously finds it's way to "initWithCoder". :-)


Thanks in advance, as usual
mdeh is offline   0 Reply With Quote
Old Jul 12, 2009, 04:36 PM   #2
kpua
macrumors 6502
 
Join Date: Jul 2006
When you encode an object, its class name is encoded along with the data that your -encodeWithCoder: method writes.

When you decode an object, the encoder first reads what the class of an object is, gets its Class meta-object and sends it -alloc, so it has a valid instance of the new object that it can send -initWithCoder:.

The NSCoder instance passed to these methods is instantiated by the archiveRootObject:toFile: and unarchiveObjectWithFile: methods. That happens implicitly behind the scenes so you don't have to worry about it.
kpua is offline   0 Reply With Quote
Old Jul 12, 2009, 07:57 PM   #3
mdeh
Thread Starter
macrumors 6502
 
Join Date: Jan 2009
Thanks kpua. If you don't mind, I'd like to explore this a little further, so that it becomes a little clearer conceptually to me.


Quote:
When you encode an object, its class name is encoded along with the data that your -encodeWithCoder: method writes.

When you decode an object, the encoder first reads what the class of an object is, gets its Class meta-object and sends it -alloc, so it has a valid instance of the new object that it can send -initWithCoder:
I guess the term "meta-object" had me puzzled. Is this simply the same as, for instance MyClass *c = [[ MyClass alloc].......] without the init? So, what ever this step returns, is now used as part of the "coder" argument in the

"-(id) initWithCoder: (NSCoder *) coder"

method? In that way, "coder" contains the ability to respond to the selectors, as well as providing the necessary data needed in the unarchiving process?

In Apple's documentation, they give this example of unArchiving.

Code:
MapView *myMapView;
NSString *archivePath = ...get the path;
myMapView = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
The issue that I would like to understand is that they "use" the return from "unarchiveObjectWithFile:", whereas in my code, I just ignore this return value, and allow "initWithCoder" to be invoked, yet it does not seem to effect the App.

Apologise if you believe you have already answered this.

Much thanks
mdeh is offline   0 Reply With Quote
Old Jul 13, 2009, 02:38 AM   #4
kpua
macrumors 6502
 
Join Date: Jul 2006
I'll let (pseudo-)code speak for itself, since it's often clearer than English.

I believe a simplified version of -unarchiveObjectWithFile: and -decodeObjectForKey: could look something like this:

Code:
+ (id)unarchiveObjectWithFile:(NSString *)file {
    NSData *fileData = [NSData dataWithContentsOfFile:file];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:fileData];
    id rootObject = [unarchiver decodeObjectForKey:@"ROOT"];
    return rootObject;
}

- (id)decodeObjectForKey:(NSString *)key {
    NSString *className = [self _readClassNameForKey:key];
    Class metaClassObject = NSClassFromString(className);
    id object = [[metaClassObject alloc] initWithCoder:self];
    return object;
}
Don't try to compile that, it's just meant to illustrate.

So, here's what's happening:

+unarchiveObjectWithFile: creates a NSKeyedUnarchiver object with the contents of the given file and then decodes the root object and returns it.

-decodeObjectForKey: reads some hidden header information that contains the encoded type (int, float, data, object, etc.), and, (for objects) the class name. The class name is then used to get a 'Class' object, which is a meta-object (my terminology may not be 100% correct here), which can be sent +alloc to allocate an object. So, in other words, the following are essentially identical:

Code:
[[NSString alloc] init];
and

Code:
Class stringClass = NSClassFromString(@"NSString");
[[stringClass alloc] init];
This pattern is very powerful because it makes instantiation of objects, for which you may not know the class of until runtime. In other languages, you have to resort to cumbersome Factory patterns to accomplish that. One more reason to enjoy Objective-C. :-)

So, if your archive contains an instance of MapView, it reads "MapView" from the archive, gets its meta-class object, instantiates and object, then sends it the -initWithCoder: message. That initWithCoder: message will be dynamically dispatched so it reaches your -initWithCoder: implementation in MapView.

Understand? Cool stuff, huh?

(Archiving and unarchiving is actually quite a bit more sophisticated than this, since there are facilities that allow you to swap one class for another one at runtime and so forth.)
kpua is offline   0 Reply With Quote
Old Jul 13, 2009, 08:08 AM   #5
mdeh
Thread Starter
macrumors 6502
 
Join Date: Jan 2009
Quote:
Originally Posted by kpua View Post
I'll let (pseudo-)code speak for itself, since it's often clearer than English.

Thank you very much for that. Much appreciated.
mdeh is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Order clarification calzohoudini Buying Tips and Advice 6 Mar 27, 2014 02:35 PM
Looking for Bootcamp Version Clarification Huntn Windows, Linux & Others on the Mac 3 Oct 27, 2013 06:40 PM
Need clarification/help with iCloud Long Johnson iCloud and Apple Services 2 Jun 8, 2013 04:33 PM
A clarification has been added to the rules annk Site and Forum Feedback 3 Sep 21, 2012 11:03 PM
Clarification on AirPlay please lowonthe456 OS X 10.8 Mountain Lion 2 Aug 11, 2012 04:18 PM

Forum Jump

All times are GMT -5. The time now is 03:10 PM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC