NSInvalidUnarchiveOperationException仅在iOS扩展中引发,而不是在主应用中引发
我已将我的NSCoding符合类“分配”的数组存档到共享(应用程序组)容器中的文件中:NSInvalidUnarchiveOperationException仅在iOS扩展中引发,而不是在主应用中引发,ios,file,cocoa-touch,swift,nskeyedarchiver,Ios,File,Cocoa Touch,Swift,Nskeyedarchiver,我已将我的NSCoding符合类“分配”的数组存档到共享(应用程序组)容器中的文件中: class private func updateSharedFiles() { let path = NSFileManager().containerURLForSecurityApplicationGroupIdentifier("group.agenda-touch")!.path! + "/widgetData" if let incompleteAssignmentsArray =
class private func updateSharedFiles() {
let path = NSFileManager().containerURLForSecurityApplicationGroupIdentifier("group.agenda-touch")!.path! + "/widgetData"
if let incompleteAssignmentsArray = self.incompleteAssignments {
NSKeyedArchiver.archiveRootObject(incompleteAssignmentsArray, toFile: path)
}
}
现在,当我的扩展名想要读取该文件时,我在该文件上调用了NSFileManager.fileExistsAtPath:,它返回true。最后,我调用NSKeyedUnarchiver.unarchiveObjectWithFile(path)as?AssignmentArray
并获取一个NSInvalidUnarchiveOperationException。问题是,当我在我的主应用程序中取消归档文件时,我没有得到这样的异常。更清楚的是,我已经将assign.swift添加到我的小部件编译源代码中。因此,我的TodayViewController知道分配是什么,但由于某种原因无法对其进行解码。
作为附录,以下是分配的NSCoding实现:
//MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.assignmentName, forKey: "assignmentName")
aCoder.encodeObject(self.assignmentDueDate, forKey: "assignmentDueDate")
aCoder.encodeObject(self.assignmentSubject, forKey: "assignmentSubject")
aCoder.encodeBool(self.completed, forKey: "assignmentCompleted")
aCoder.encodeObject(self.creationDate, forKey: "assignmentCreationDate")
aCoder.encodeInteger(self.assignmentType.rawValue, forKey: "assignmentType")
aCoder.encodeBool(self.earmarkedForDeletion, forKey: "assignmentEarmarked")
aCoder.encodeObject(self.modificationDates, forKey: "assignmentModificationDates")
}
required convenience init(coder aDecoder: NSCoder) {
let assignmentName = aDecoder.decodeObjectForKey("assignmentName") as String
let assignmentDueDate = aDecoder.decodeObjectForKey("assignmentDueDate") as NSDate
let assignmentSubject = aDecoder.decodeObjectForKey("assignmentSubject") as String
let completed = aDecoder.decodeBoolForKey("assignmentCompleted")
self.init(name:assignmentName,dueDate:assignmentDueDate,subject:assignmentSubject,completed:completed)
self.creationDate = aDecoder.decodeObjectForKey("assignmentCreationDate") as NSDate
let assignmentTypeRaw = aDecoder.decodeIntegerForKey("assignmentType")
self.assignmentType = AssignmentType(rawValue: assignmentTypeRaw)!
self.earmarkedForDeletion = aDecoder.decodeBoolForKey("assignmentEarmarked")
self.modificationDates = aDecoder.decodeObjectForKey("assignmentModificationDates") as Dictionary<String,NSDate>
}
//标记:NSCoding
带编码器的func编码器(aCoder:NSCoder){
aCoder.encodeObject(self.assignmentName,forKey:“assignmentName”)
aCoder.encodeObject(self.assignmentDueDate,forKey:“assignmentDueDate”)
aCoder.encodeObject(self.assignmentSubject,forKey:“assignmentSubject”)
aCoder.encodeBool(self.completed,forKey:“assignmentCompleted”)
aCoder.encodeObject(self.creationDate,forKey:“assignmentCreationDate”)
aCoder.encodeInteger(self.assignmentType.rawValue,forKey:“assignmentType”)
aCoder.encodeBool(self.earmarkedForDeletion,forKey:“assignmentEarmarked”)
aCoder.encodeObject(self.modificationDates,forKey:“assignmentModificationDates”)
}
所需的便利初始化(编码器aDecoder:NSCoder){
让assignmentName=aDecoder.decodeObjectForKey(“assignmentName”)作为字符串
让assignmentDueDate=aDecoder.decodeObjectForKey(“assignmentDueDate”)作为NSDate
让assignmentSubject=aDecoder.decodeObjectForKey(“assignmentSubject”)作为字符串
let completed=aDecoder.decodeBoolForKey(“assignmentCompleted”)
self.init(名称:assignmentName,dueDate:assignmentDueDate,主题:assignmentSubject,completed:completed)
self.creationDate=aDecoder.decodeObjectForKey(“assignmentCreationDate”)作为NSDate
让assignmentTypeRaw=aDecoder.decodeIntegerWorky(“assignmentType”)
self.assignmentType=assignmentType(原始值:assignmentTypeRaw)!
self.earmarkedForDeletion=aDecoder.decodeboolforky(“assignmentEarmarked”)
self.modificationDates=aDecoder.decodeObjectForKey(“assignmentModificationDates”)作为字典
}
我也有同样的问题。我试图从编译源代码中删除和添加该文件。也不行。你找到解决办法了吗
我的问题唯一的不同之处是:我试图解构对象xxx的NSArray。当在主应用程序中存档和取消存档或在WatchKit应用程序中存档和取消存档时,它可以工作,但当我在主应用程序中存档并在WatchKit应用程序中取消存档时(以及其他情况下),它不能工作
在我的应用程序组中,通过NSUserDefaults交换对象是有效的。我只在使用对象xxx的NSArray的NSKeyedArchiver和NSKeyedUnachiver时遇到此问题
*由于未捕获的异常“NSInvalidUnarchiveOperationException”而终止应用程序,原因:'*-[nsKeyedUnachiver decodeObjectForKey:]:无法解码类xxx的对象
编辑:我解决了使对象符合NSSecureCodeding的问题。因此,我替换了
propertyName=aDecoder.decodeObjectForKey(“propertyName”)
与
propertyName=aDecoder.decodeObjectOfClass(NSString.self,forKey:“propertyName”)作为NSString
并补充说
class func supportsSecureCoding() -> Bool {
return true
}
我还使用主应用程序的选项在ApplicationFinishLaunching中以及WatchKitApp的第一个WKInterfaceController中设置了NSKeyedUnachiver和NSKeyedArchiver的类名
NSKeyedArchiver.setClassName("Song", forClass: Song.self)
NSKeyedUnarchiver.setClass(Song.self, forClassName: "Song")
我也有同样的问题。 总结前面的回答和评论,解决方案在于
setClass
/setClassName
语句。我将编码包装为以下示例代码(Swift 5)中的函数:
等等,我不认为这是一个答案。对不起,我不能对原来的问题发表评论,因为声誉不好。:)我编辑了这篇文章,因此它可能包含原始问题的答案。只需调用
NSKeyedArchiver.setClassname
和NSKeyedUnarchiver.setClass
。采用NSSecureCoding
不会有任何区别。潜在的问题是,类名包括模块一起存储,并且您的扩展和主应用程序具有不同的模块名。
NSKeyedArchiver.setClassName("Song", forClass: Song.self)
NSKeyedUnarchiver.setClass(Song.self, forClassName: "Song")
import Foundation
public class User: NSObject, NSSecureCoding
{
public var id: String
public var name: String
public init(id: String, name: String)
{
self.id = id
self.name = name
}
// NSSecureCoding
public static var supportsSecureCoding: Bool { return true }
public func encode(with coder: NSCoder)
{
coder.encode(id , forKey: "id")
coder.encode(name, forKey: "name")
}
public required init?(coder: NSCoder)
{
guard
let id = coder.decodeObject(forKey: "id") as? String,
let name = coder.decodeObject(forKey: "name") as? String
else {
return nil
}
self.id = id
self.name = name
}
// (Un)archiving
public static func decode(from data: Data) -> Self?
{
NSKeyedUnarchiver.setClass(Self.self, forClassName: String(describing: Self.self))
return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? Self
}
public func encode() -> Data?
{
NSKeyedArchiver.setClassName(String(describing: Self.self), for: Self.self)
return try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: Self.supportsSecureCoding)
}
}