NSInvalidUnarchiveOperationException仅在iOS扩展中引发,而不是在主应用中引发

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 =

我已将我的NSCoding符合类“分配”的数组存档到共享(应用程序组)容器中的文件中:

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)
    }
}