NSKeyedArchiver 弃用方法问题

NSKeyedArchiver deprecated method problem

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

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

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

   ...        
    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:”如果我使用新代码,它编译并运行良好,但用户数据不会重新出现。

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

If encoding has not yet finished, invoking this property calls finishEncoding and populates this property with the encoded data

它returns一个可以写入磁盘的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 "This decoder will only decode classes that adopt NSSecureCoding. Class 'Persistance' does not adopt it." UserInfo={NSDebugDescription=This decoder will only decode classes that adopt NSSecureCoding. Class 'Persistance' does not adopt it.}