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

Posted

技术标签:

【中文标题】如何在 iOS 12 中替换 NSKeyedArchiver 的初始化程序 init(forWritingWith:) 来编码 CKRecord 的元数据【英文标题】:How to replace NSKeyedArchiver's initializer init(forWritingWith:) in iOS 12 to encode the metadata of a CKRecord 【发布时间】:2018-12-24 15:13:38 【问题描述】:

ios 12 中,NSKeyedArchiver 的初始化程序 init(forWritingWith:) 已被弃用。 Xcode 10 建议用新的初始化程序 init(requiringSecureCoding:) 替换它。问题是这个初始化器只设置了 NSCoder 对象的 requiresSecureCoding 属性的值,但它没有设置将包含编码数据的 NSMutableData 对象。以下是 Apple 提出的对 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(requiringSecureCoding:) 初始化程序替换 init(forWritingWith:) 初始化程序,我会得到一个 NSKeyedArchiver 对象,但该对象不与任何 NSMutableData 对象关联,因此我没有得到记录的元数据。我不确定如何完成代码以将 NSKeyedArchiver 对象生成的数据转换为 NSMutableData 对象。

【问题讨论】:

【参考方案1】:

对于现在的几个版本,NSKeyedArchiver 有一个encodedData method,它在存档器上调用-finishEncoding,并将存档器创建的最终编码数据返回给您。这就是通过-[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 以便仅对自身的一个子集进行编码。在编码对象的一般情况下,您将使用the new NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:) method:

let data = try NSKeyedArchiver.archivedData(withRootObject: /* object */, requiringSecureCoding: true)

相当于

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

【讨论】:

Re:你的“根对象”等价物,知道为什么如果我立即解码(创建副本)我会得到错误-decodeValueOfObjCType:at:size: only defined for abstract class. Define -[NSKeyedArchiver decodeValueOfObjCType:at:size:]!?例如:let copy = coder.decodeObject() 编辑:(试图复制UIView的子类) @DavidJames 根据错误,当您应该使用NSKeyedUnarchiver 时,您似乎正在尝试从NSKeyedArchiver(仅进行编码)解码。如果您可以分享更多代码,可能会更容易指出。 是的,就是这样!谢谢你。新的工作代码:let copy = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject:view, requiringSecureCoding:false))

以上是关于如何在 iOS 12 中替换 NSKeyedArchiver 的初始化程序 init(forWritingWith:) 来编码 CKRecord 的元数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 coreData iOS 中替换 abort() 函数

回退如何与 socket.io 一起工作?

最新的 iOS 版本 (12.4) 不推荐使用 didUpdateLocationsTo: from: 方法。如何用 didUpdateLocations 替换它?

如何在 iOS 上的 UIScrollView 中正确替换 UIImageView 中的图像

IOS,如何在数组中的 dic 中循环 dic 以替换空字符串的空值

swift - UIWebView 和 WKWebView(iOS12 之后替换UIWebView)