【问题标题】:Custom object inheriting NSMutableDictionary and serialized with NSKeyedArchiver can't be deserialized继承 NSMutableDictionary 并用 NSKeyedArchiver 序列化的自定义对象无法反序列化
【发布时间】:2017-03-19 11:28:17
【问题描述】:

类未正确解档。 请参阅下面的代码示例。

@interface A : NSMutableDictionary 
@end

@implementation A
- (void)encodeWithCoder:(NSCoder *)aCoder
{

}

- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init]) {

    }   
    return self;
}
@end


@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    A *a = [[A alloc] init];

    NSMutableDictionary *dict = [NSMutableDictionary new];
    dict[@"some"] = a;

    NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:dict];

    dict = [NSKeyedUnarchiver unarchiveObjectWithData:archive];

    NSLog(@"%@",dict);
}

在 unarchiveObjectWithData 调用之后,dict 包含对键 @"some" 但对象是 NSMutableDictionary 而不是 A 类。并且在 unarchiveObjectWithData 调用时不会发生 initWithCoder 调用。 那么,make it code 是如何工作的呢?为什么不反序列化继承 NSMutableDictionary 的类?

【问题讨论】:

    标签: objective-c nsmutabledictionary nscoding nskeyedarchiver nskeyedunarchiver


    【解决方案1】:

    这个方法:

    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
    }
    

    包含对象对自身进行编码的指令,也就是说,“不要做任何事情”。应该说的是:

    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        // perform the inherited behavior or encoding myself
        [super encodeWithCoder:encoder];
    }
    

    再次编辑,这个测试类以最简单的方式继承NSMutableDictionary:通过在其实现中隐藏一个可变字典实例并提供原始方法(PLUS encodeWithCoder

    #import "MyDict.h"
    
    @interface MyDict ()
    @property(strong) NSMutableDictionary *internalDictionary;
    @end
    
    @implementation MyDict
    
    // changed to the default init for the "new" constructor
    - (id)init {
        self = [super init];
        if (self) {
            _internalDictionary = [[NSMutableDictionary alloc] init];
        }
        return self;
    }
    
    - (NSUInteger)count {
        return [self.internalDictionary count];
    }
    
    - (id)objectForKey:(id)aKey {
        return [self.internalDictionary objectForKey:aKey];
    }
    
    - (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey {
        return [self.internalDictionary setObject:anObject forKey:aKey];
    }
    
    - (void)removeObjectForKey:(id)aKey {
        return [self.internalDictionary removeObjectForKey:aKey];
    }
    
    - (NSEnumerator *)keyEnumerator {
        return [self.internalDictionary keyEnumerator];
    }
    
    // added encoding of the internal representation
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        [super encodeWithCoder:aCoder];
        [aCoder encodeObject:_internalDictionary forKey:@"internalDictionary"];
    }
    
    // added decoding of the internal representation
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            _internalDictionary = [aDecoder decodeObjectForKey:@"internalDictionary"];
        }
        return self;
    }
    
    - (Class)classForCoder {
        return self.class;
    }
    
    @end
    

    再次编辑,这次完全是您的测试:

    MyDict *a = [MyDict new];
    a[@"hi"] = @"there";
    
    NSMutableDictionary *dict = [NSMutableDictionary new];
    dict[@"some"] = a;
    NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:dict];
    dict = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
    NSLog(@"%@", dict);
    

    日志...

    { 一些= { 嗨=那里; }; }

    【讨论】:

    • 对不起,它不起作用。首先,你检查过这个吗?我确实尝试过,但崩溃了。
    • 崩溃说什么?您是否实现了所有 NSMutableDictionary 原始方法?请记住,您还必须实现所有不可变的字典原语方法。
    • @SashaSewerow - 添加了证明正确性的代码。
    • 我用这个检查了你的代码:MyDict *a = [MyDict new]; NSMutableDictionary *dict = [NSMutableDictionary new]; dict[@"some"] = a; NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:dict]; dict = [NSKeyedUnarchiver unarchiveObjectWithData:archive];结果,dict 有键值对,键是“一些”值是一些 NSMutableDictionary 但不是 MyDict 对象。并且 - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder of MyDict 没有被调用
    • 子类化字典有点棘手。你的例子使用了 new,我的使用了 initWithCapacity(由便捷构造函数dictionary 调用) 接下来,我只是演示了在 encode 方法中调用 super 的不崩溃,所以我没有对内部字典进行编码。最后,在您的测试代码中,您没有为可变子类设置任何值。我将进行编辑以演示您的测试工作。同时,浏览子类字典上的类文档很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多