NSKeyedArchiver 不推荐使用的方法问题

Posted

技术标签:

【中文标题】NSKeyedArchiver 不推荐使用的方法问题【英文标题】:NSKeyedArchiver deprecated method problem 【发布时间】:2020-12-24 05:54:10 【问题描述】:

只是一点背景信息。几年前我失去了说话的能力,并学会了如何专门编写代码来为自己制作一个好的文本到语音应用程序。令人惊讶的是,许多其他人发现它很有用。苹果每周报告大约 15,000 次会话。顺便说一句,它是免费的。

在我开始学习的时候,目标 C 是当前的语言,所以这就是我学到的。我现在正在学习 Swift,但我还没有准备好重新编写我的应用程序。我只是还不够了解。

我正在尝试更新应用程序,但 NSKeyedArchiver 有一个已弃用的方法,我一直在尝试修复它。以下是显示代码的代码 sn-p。这在用户关闭应用程序时运行并且应该保存他们的数据:

   ...        
    persistence.field19 = [NSNumber numberWithBool:self.autoOn];
   
        persistence.field20 = [NSNumber numberWithBool:self.instructionShown];
        
        NSMutableData *data = [[NSMutableData alloc] init];
        //NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    
        NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false];
    
    
        
        [archiver encodeObject:persistence
                        forKey:kDataKey];
        [archiver finishEncoding];
        [data writeToFile:[self dataFilePath]
               atomically:YES];
    

我有“initForWritingWithMutableData:data”这一行,并被告知用“initRequiringSecureCoding:Bool”替换。这很高兴 Xcode 删除了警告,但不再保存用户设置和数据。我相信这是因为我曾经将 NSMutableData 分配给存档器,但现在不再这样做了。我在文档中发现以下可能会有所帮助,但我不知道如何实现:

(NSData *)archivedDataWithRootObject:(id)object 
                 requiringSecureCoding:(BOOL)requiresSecureCoding 
                                 error:(NSError * _Nullable *)error;

当应用再次启动时,我会加载他们的设置并使用以下内容保存数据:

// Restore settings
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) 
    NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:NULL];
//initForReadingWithData:data];

“initForReadingWithData:data”也被弃用了,我被告知使用“initForReadingFromData:error:”方法代替它。我“认为”这很好。

非常感谢任何帮助或建议。

更新:感谢 TheNextman 的建议,存档器正在工作。这是当前代码:

    ...
    persistence.field20 = [NSNumber numberWithBool:self.instructionShown];
    
//    NSMutableData *data = [[NSMutableData alloc] init];
//    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];

    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false];
    [archiver encodeObject:persistence forKey:kDataKey];
        [archiver finishEncoding];

    NSData* data = [archiver encodedData];
    [data writeToFile:[self dataFilePath] atomically:YES];

    
//    [archiver encodeObject:persistence
//                    forKey:kDataKey];
//    [archiver finishEncoding];
//    [data writeToFile:[self dataFilePath]
//           atomically:YES];

但要使其正常工作,我必须继续使用已弃用的未归档代码。

    // Restore settings
    NSString *filePath = [self dataFilePath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) 
        NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
//        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:NULL];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];

“initForReadingWithData:data”再次被弃用,我被告知使用“initForReadingFromData:error:”如果我使用新代码,它可以编译并运行良好,但用户数据不会重新出现。

【问题讨论】:

【参考方案1】:

我没有测试它,但我认为你想要 encodedData 属性。

如果编码尚未完成,则调用此属性会调用 finishEncoding 并使用编码数据填充此属性

它返回一个可以写入磁盘的NSData 指针

NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:false];
[archiver encodeObject:persistence forKey:kDataKey];

NSData* data = [archiver encodedData];
[data writeToFile:[self dataFilePath] atomically:YES];

然后我像这样解压对象:

NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:nil];
[unarchiver setRequiresSecureCoding:NO];
Persistance* p = [unarchiver decodeObjectForKey:kDataKey];

请注意,我们必须明确告诉取消存档者我们不需要安全编码(正如为存档者指定的那样)。

如果您查看文档(实际上,例如上面的 initForReadingFromData:error: 函数),许多函数都带有一个可选的“错误”参数。

您可以传入一个NSError 指针,然后检查它包含的内容,如果您没有得到预期的结果。例如:

NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:nil];
//[unarchiver setRequiresSecureCoding:NO]
NSError* err = nil;
Persistance* p = [unarchiver decodeTopLevelObjectOfClass:[Persistance class] forKey:kDataKey error:&err];
NSLog(@"%@ %@", p, err);

在这种情况下,您会看到问题:

(null) Error Domain=NSCocoaErrorDomain Code=4864 "这个解码器只会解码采用 NSSecureCoding 的类。类 'Persistance' 不采用它。" UserInfo=NSDebugDescription=此解码器只会解码采用 NSSecureCoding 的类。 “持久性”类不采用它。

【讨论】:

我正在接受您的建议,并且已经完成了一半。您能否建议更改我的 NSKeyedUnarchiver 代码。因为您对 NSKeyedArchiver 的建议仅在我使用已弃用的 NSKeyedUnarchiver 时才有效。这有意义吗?

以上是关于NSKeyedArchiver 不推荐使用的方法问题的主要内容,如果未能解决你的问题,请参考以下文章

ios NSKeyedArchiver 释放 = 错误访问

用NSKeyedArchiver存储数据(归档)

Swift NSKeyedArchiver toFile:未解析的标识符

NSKeyedArchiver

Xcode-project 不使用 NSKeyedArchiver 存档,但 Playground 可以

NSKeyedArchiver 只编码数组的一部分