我已将符合NSCoding的类“Assignment”的数组存档到共享(App Groups)容器中的文件:
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。问题是,当我在主应用程序中取消归档文件时,我没有得到这样的异常。为了清楚起见,我已经将Assignment.swift添加到我的小部件的编译源中。所以我的TodayViewController知道Assignment是什么,但由于某种原因无法解码它。
作为附录,这里是分配的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>
}
答案 0 :(得分:2)
我有完全相同的问题。我试图删除并从编译源添加文件。也不工作。你找到了解决方案吗?
唯一不同于我的问题:我尝试取消归档NSArray对象xxx。它适用于在主应用程序中归档和取消归档,或在WatchKit应用程序中归档和取消归档,但不是在我将其归档到主应用程序并在WatchKit应用程序中取消归档(以及其他方式)时。
let defaults: NSUserDefaults = NSUserDefaults(suiteName: "group.name")!
if let object: NSData = defaults.objectForKey(ArrayKey) as? NSData {
if let array: AnyObject = NSKeyedUnarchiver.unarchiveObjectWithData(object) {
return array as NSArray
}
}
return NSArray()
通过我的应用程序组中的NSUserDefaults交换对象。我只使用带有对象xxx的NSArray的NSKeyedArchiver和NSKeyedUnarchiver遇到此问题。
*由于未捕获的异常'NSInvalidUnarchiveOperationException'而终止应用程序,原因:'* - [NSKeyedUnarchiver decodeObjectForKey:]:无法解码类xxx的对象
编辑:我解决了使我的对象符合NSSecureCoding的问题。因此我取代了
propertyName = aDecoder.decodeObjectForKey("propertyName")
带
propertyName = aDecoder.decodeObjectOfClass(NSString.self, forKey: "propertyName") as NSString
并添加了
class func supportsSecureCoding() -> Bool {
return true
}
我还在主app的applicationFinishLaunchingWithOptions和WatchKitApp的第一个WKInterfaceController中设置了NSKeyedUnarchiver和NSKeyedArchiver的className
NSKeyedArchiver.setClassName("Song", forClass: Song.self)
NSKeyedUnarchiver.setClass(Song.self, forClassName: "Song")
答案 1 :(得分:0)
我也遇到了完全相同的问题。
总结以前的答案和评论,解决方案在于 setClass
/setClassName
语句。我在下面的示例代码(Swift 5)中将我的编码包装为函数:
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)
}
}