如何在iOS 12中替换NSKeyedArchiver的初始化程序init(forWritingWith :)以编码CKRecord的元数据

16
在iOS 12中,NSKeyedArchiver的初始化程序init(forWritingWith:)已被弃用。Xcode 10建议使用新的初始化程序init(requiringSecureCoding:)来代替它。问题在于,该初始化程序仅设置NSCoder对象的requiresSecureCoding属性的值,而不设置将包含编码数据的NSMutableData对象。以下是苹果提供的用于编码CKRecord(CloudKit记录)元数据的原始代码:
let data = NSMutableData()
let coder = NSKeyedArchiver.init(forWritingWith: data)
coder.requiresSecureCoding = true
record.encodeSystemFields(with: coder)
coder.finishEncoding()

CKRecord类的encodeSystemFields方法需要一个NSKeyedArchiver对象(一个NSCoder子类),并将编码数据存储在与此对象关联的NSMutableData对象中。如果我将init(forWritingWith:)初始化器替换为init(requiringSecureCoding:)初始化器,则会获得一个NSKeyedArchiver对象,但是该对象未与任何NSMutableData对象相关联,因此我无法获得记录的元数据。我不确定如何完成代码以将NSKeyedArchiver对象生成的数据放入NSMutableData对象中。

1个回答

26

从几个版本开始,NSKeyedArchiver 已经有了一个 encodedData方法,它调用 archiver 上的 -finishEncoding 方法,并将 archiver 创建的最终编码数据返回给您。当通过 -[NSKeyedArchiver init] 进行初始化时,这是获取完成数据的方式:

let coder = NSKeyedArchiver()
/* encode stuff */
let data = coder.encodedData
这消除了对NSMutableData变量的需求。随着这个更新,这种可变数据变体已被弃用,更青睐于新的范例。因此,不必再编写以下内容。
let data = NSMutableData()
let coder = NSKeyedArchiver.init(forWritingWith: data)
coder.requiresSecureCoding = true
record.encodeSystemFields(with: coder)
coder.finishEncoding()

你会写

let coder = NSKeyedArchiver(requiringSecureCoding: true)
record.encodeSystemFields(with: coder)
let data = coder.encodedData
.requiresSecureCoding 的手动赋值和手动调用 finishEncoding() 都不再需要。
请注意,这种操作仅在调用 CKRecord.encodeSystemFields(with:) 时才是必需的,该方法明确地接受一个 NSCoder,以便仅对其进行子集编码。在一般情况下,您应该使用 新的 NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:) 方法 进行编码:
let data = try NSKeyedArchiver.archivedData(withRootObject: /* object */, requiringSecureCoding: true)

相当于

let coder = NSKeyedArchiver(requiringSecureCoding: true)
coder.encodeObject(/* object */, forKey: NSKeyedArchiveRootObjectKey)
let data = coder.encodedData

关于您的“根对象”等价物,您有任何想法为什么如果我立即解码它(以创建副本),我会得到错误-decodeValueOfObjCType:at:size: only defined for abstract class. Define -[NSKeyedArchiver decodeValueOfObjCType:at:size:]!?例如:let copy = coder.decodeObject() - David James
(尝试复制“UIView”的子类) - David James
@DavidJames 根据错误信息,看起来你正在尝试从 NSKeyedArchiver(仅进行编码)解码,而你应该使用 NSKeyedUnarchiver。如果你能分享更多的代码,可能会更容易指出问题所在。 - Itai Ferber
是的,就是这样!谢谢您。新的、可运行的代码:let copy = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject:view, requiringSecureCoding:false)) - David James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接