encodeWithCoder is not called in derived class of the NSMutableDictionary

杀马特。学长 韩版系。学妹 提交于 2019-12-11 00:50:00

问题


Basically I am using some open source code called OrderedDictionary that is derived from NSMutableDictionary. Then I want to save the ordered dictionary data to NSUserDefaults by adding encode and decode method to the OrderedDictionary class. However, I realized the encode and decode methods are not being called, as a result, the decoded dictionary is no longer ordered. Below is my code:

@interface OrderedDictionary : NSMutableDictionary <NSCopying, NSCoding>
{
    NSMutableDictionary *dictionary;
    NSMutableArray *array;
}

In the implementation file:

/**
 * encode the object
 **/
- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
    [coder encodeObject:dictionary forKey:@"dictionary"];
    [coder encodeObject:array forKey:@"array"];
}

/**
 * decode the object
 */
- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self != nil)
    {
        dictionary = [coder decodeObjectForKey:@"dictionary"];
        array = [coder decodeObjectForKey:@"array"];
    }   
    return self;
}

Quick example code for using this:

dictionary = [[OrderedDictionary alloc] init];
[dictionary setObject:@"one" forKey:@"two"];
[dictionary setObject:@"what" forKey:@"what"];
[dictionary setObject:@"7" forKey:@"7"];
NSLog(@"Final contents of the dictionary: %@", dictionary);

if ([[NSUserDefaults standardUserDefaults] objectForKey:@"myDictionary"] == nil)
{
    [[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:dictionary] 
                                          forKey:@"myDictionary"];
}
else
{
    NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];

    NSData *savedDictionary = [currentDefaults objectForKey:@"myDictionary"];

    if (savedDictionary != nil)
    {
        OrderedDictionary *oldData = [NSKeyedUnarchiver unarchiveObjectWithData:savedDictionary];
        if (oldData != nil) 
        {
            NSLog(@"Final contents of the retrieved: %@", oldData);

        } 
    }
}

The thing is, the final retrievedDictionary does NOT have the original data order and the encode and decode methods are not called at all.

Thanks for any help in advance! :)


回答1:


There's an NSObject method called -classForCoder that you need to override in OrderedDictionary. From the docs:

classForCoder
Overridden by subclasses to substitute a class other than its own during coding.

-(Class)classForCoder
Return Value
The class to substitute for the receiver's own class during coding.

Discussion
This method is invoked by NSCoder. NSObject’s implementation returns the receiver’s class. The private subclasses of a class cluster substitute the name of their public superclass when being archived.

That last line is the key. So, in OrderedDictionary.m:

- (Class)classForCoder 
{  
    return [self class]; // Instead of NSMutableDictionary
} 

Also, if you're not using ARC, make sure you retain the objects coming back from -decodeObjectForKey. As rob mayoff mentions below, you shouldn't call [super initWithCoder:] (or [super encodeWithCoder:'). I also changed the key strings to avoid collisions.

- (id)initWithCoder:(NSCoder *)coder
{
    if (self != nil)
    {
        dictionary = [[coder decodeObjectForKey:@"OrderedDictionary_dictionary"] retain];
        array = [[coder decodeObjectForKey:@"OrderedDictionary_array"] retain];
    }   
    return self;
}



回答2:


You are possibly creating a new OrderedDictionary with the wrong initializer, initWithDictionary:. Try this instead:

OrderedDictionary *oldData = [NSKeyedUnarchiver unarchiveObjectWithData: savedDictionary];
if (oldData != nil) 
{
    NSLog(@"Final contents of the retrieved: %@", oldData);
}

Make sure initWithDictionary: expects OrderedDictionary as an argument. My guess is that it expects an NSDictionary.

Edit: the code to save the defaults should include something like this:

OrderedDictionary *myDict = ...;
NSData* data = [NSKeyedArchiver archivedDataWithRootObject: myDict];
[[NSUserDefaults standardDefaults] setObject: data forKey: @"myDictionary"];


来源:https://stackoverflow.com/questions/10004783/encodewithcoder-is-not-called-in-derived-class-of-the-nsmutabledictionary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!