如何在 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() 函数
最新的 iOS 版本 (12.4) 不推荐使用 didUpdateLocationsTo: from: 方法。如何用 didUpdateLocations 替换它?
如何在 iOS 上的 UIScrollView 中正确替换 UIImageView 中的图像