【问题标题】:iOS: how to serialize a non-NSCoding compliant objectiOS:如何序列化非 NSCoding 兼容的对象
【发布时间】:2012-09-18 09:40:56
【问题描述】:

我已经环顾四周,在这里找到了答案:

Correct way to save/serialize custom objects in iOS

但这仅适用于用户创建的自定义对象。我的问题是序列化“SKProduct”,这是一个不符合 NSCoding 的派生类。具体来说,我遇到的确切错误:

-[SKProduct encodeWithCoder:]: unrecognized selector sent to instance 0x4027160

有人有类似经历吗?

【问题讨论】:

    标签: ios serialization nscoding


    【解决方案1】:

    我会在这个答案的开头说可能有更简单的方法;但是归档和取消归档期间的类替换是您可以采取的一种方法。

    在归档期间,您可以选择设置符合NSKeyedArchiverDelegate 协议的委托。所有方法都是可选的。代理在编码期间收到消息archiver:willEncodeObject: 消息。如果您希望在归档期间替换一个类,您可以创建一个替换对象并将其返回。否则只返回原始对象。

    在您的情况下,您可以为 SKProduct 创建一个“影子对象”,它封装了您对序列化感兴趣的原始类的任何属性。然后在归档期间替换该类。在取消归档期间,您可以反转该过程并返回SKProduct

    为了便于说明,下面是一个示例。请注意,我省略了反向替换部分 - 但如果您阅读 NSKeyedUnarchiverDelegate 上的文档,我认为会很清楚。

    #import <Foundation/Foundation.h>
    
    @interface NoncompliantClass:NSObject
    @property (nonatomic,assign) NSInteger foo;
    @end
    
    @implementation NoncompliantClass
    @synthesize foo = _foo;
    @end
    
    @interface CompliantClass:NSObject <NSCoding>
    @property (nonatomic,assign) NSInteger foo;
    @end
    
    @implementation CompliantClass
    @synthesize foo = _foo;
    
    - (void)encodeWithCoder:(NSCoder *)coder {
        [coder encodeInteger:self.foo forKey:@"FooKey"];
    }
    
    - (id)initWithCoder:(NSCoder *)coder {
        self = [super init];
        if( !self ) { return nil; }
    
        _foo = [coder decodeIntegerForKey:@"FooKey"];
        return self;
    }
    
    @end
    
    @interface ArchiverDelegate:NSObject <NSKeyedArchiverDelegate>
    @end
    
    @implementation ArchiverDelegate
    - (id)archiver:(NSKeyedArchiver *)archiver willEncodeObject:(id)object {
        NSString *objClassName = NSStringFromClass([object class]);
        NSLog(@"Encoding %@",objClassName);
        if( [object isMemberOfClass:[NoncompliantClass class]] ) {
            NSLog(@"Substituting");
            CompliantClass *replacementObj = [CompliantClass new];
            replacementObj.foo = [object foo];
            return replacementObj;
        }
        return object;
    }
    @end
    
    int main(int argc, char *argv[]) {
        @autoreleasepool {
            NoncompliantClass *cat1 = [NoncompliantClass new];
            NoncompliantClass *cat2 = [NoncompliantClass new];
            NSArray *herdableCats = [NSArray arrayWithObjects:cat1,cat2,nil];
    
            ArchiverDelegate *delegate = [ArchiverDelegate new];
            NSMutableData *data = [NSMutableData data];
            NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
            [archiver setDelegate:delegate];
            [archiver encodeObject:herdableCats forKey:@"badKitties"];
            [archiver finishEncoding];
        }
    }
    

    这个日志:

    2012-09-18 05:24:02.091 TestSerialization[10808:303] Encoding __NSArrayI
    2012-09-18 05:24:02.093 TestSerialization[10808:303] Encoding NoncompliantClass
    2012-09-18 05:24:02.093 TestSerialization[10808:303] Substituting
    2012-09-18 05:24:02.094 TestSerialization[10808:303] Encoding NoncompliantClass
    2012-09-18 05:24:02.094 TestSerialization[10808:303] Substituting
    

    【讨论】:

    • 感谢您的即时反馈,这种方法似乎回答了我的问题,但我认为这太过分了。我的第二个想法是将属性手动存储到 NSDictionary 对象中,然后将其序列化。由于此方法还涉及手动编码每个属性,因此我也将无法再次编码不符合 NSCoding 的对象。 (我正在尝试找到一种将整个 SKProduct 编码到最深层次的简单方法)
    • 更大的问题 - 我之前错过的一个问题 - 是您将如何取消归档 SKProduct,无论您采取何种路径到达那里。它的所有属性似乎都是只读的。 (可能有充分的理由,如果你考虑一下......)
    猜你喜欢
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多