Domanda

I was wondering how NSCoder would handle an object that was shared and encoded by multiple objects the next time it was decoded. Will it make two copies of the object, or will one object be decoded and shared between all other objects that decode it?

I've provided a small example of a situation like this below.

Example:

  1. Application starts up
  2. Object A and Object B set Object C as their delegate
  3. Application receives termination notification.
  4. Object A and Object B encode themselves and all of their objects (including their delegates)
  5. Application shuts down and restarts
  6. Object A and Object B decode themselves and all of their objects (including their delegates)

Would Object A and Object B both share the same decoded object after step 6 or would they each have their own copy of it?

È stato utile?

Soluzione

They'll share a reference to the same object (unless you go to lengths to change that behavior).

I.e. NSCoding can deal with fully cyclic, omni-directional, complexly connected, object graphs (as long as all graph participants correctly support NSCoding).

Note that encoding delegates is highly atypical. Delegates are usually connected to an unarchived object graph after anarchival and delegates act as a sort of conduit between your archived model layer (or archived view layer, in the case of IB -- the story is more complex, really, for XIB files... but... close enough) and the rest of your app.

Altri suggerimenti

This is a great question, and I always wondered about it myself. So, I wrote a small test program to try it out. Four classes: ClassA, ClassB, ClassC, and MyBaseClass. ClassA, ClassB, and ClassC inherit from MyBaseClass which conforms to NSCoding and provides two properties: name and age. The A, B, and C classes are identical except that ClassA and ClassB also contain a reference to an instance of ClassC. ClassA and ClassB also override initwithCoder: and encodeWithCoder: to decode and encode their references to the instance of ClassC. Here is what the top-level code looks like:

ClassA *a = [[ClassA alloc] initWithName:@"Mr. A" age:11];
ClassB *b = [[ClassB alloc] initWithName:@"Mrs. B" age:22];
ClassC *c = [[ClassC alloc] initWithName:@"Ms. C" age:33];

b.c = c;
a.c = c;

NSArray *rootObject = @[a, b, c];
NSString *const kFilePath = @"/Users/myname/Documents/testarchive";
BOOL result = [NSKeyedArchiver archiveRootObject:rootObject toFile:kFilePath];
NSLog(@"result = %@", (result) ? @"YES" : @"NO");

NSArray *newRootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:kFilePath];
NSLog(@"new root object = %@", newRootObject);

The objects serialize and deserialize perfectly. Also, after deserializing, a.c and b.c point to the same instance of ClassC — that is, their object pointers have the same address.

Apparently, within NSKeyedArchiver's encodeObject:forKey:, a test is done to see if the object being encoded isEqualTo: a previously encoded object, and if it is, a reference is stored instead of a complete object. The converse must happen in NSKeyedUnarchiver's decodeObject:forKey:. Very cool!

I don't think the first answer is entirely correct. According to Apple's documentation, "The serialization only preserves the values of the objects and their position in the hierarchy. Multiple references to the same value object might result in multiple objects when deserialized".

So it's not guaranteed that a single object serialized will result in a single object when deserialized from those multiple NSCoders.

If you're implementation is anything like your example then you may not be thinking about things quite right. If you think about the logical organization of an application it might make sense that multiple objects could share the same delegate. But generally I wouldn't expect somebody to use the NSCoder protocol to encode/decode delegates. Normally I would expect the delegate to encode/decode the objects for which it is the delegate.

For instance let's look at NSTableView. Perhaps the user gets the ability to configure how the NSTableView is displayed (perhaps the user is allowed to resize columns or choose which columns are displayed). This is useful information that you might want to save and restore using the NSCoding protocol. NSTableView's also have delegates. The delegate should be a controller (from the MVC paradigm) and should never really need to be encoded/decoded using NSCoding because it is generic code that does not have to maintain any runtime state.

So Ideally you create your delegate/controller using an init method. It realizes it needs to configure a NSTableView to look the way it did the last time the user configured it, so it pulls an old table view from disk using NSCoding and then displays that to the user just as it was the last time they saw it.

I think the same goes for the Model layer in the MVC Paradigm. Again, the Controller layer should be decoding the model objects which are specific to what the user has done through their use of the application.

It sounds more like you are trying to instantiate the controller layer from the model or perhaps view layer. It doesn't really make sense.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top