NSSecureCoding实现问题:解码TextDocumentClass数组返回nil求助
NSSecureCoding解码TextDocumentClass数组返回nil的问题
实现NSSecureCoding时,解码后无法获取TextDocumentClass类型数组,返回值始终为nil。尝试过在aDecoder.decodeObject中传入[TextDocumentClass.self]、NSArray.self等参数均无效,同时自定义了MyClassValueTransformer以支持默认NSSecureUnarchiveFromDataTransformer未包含的类,相关代码及错误日志如下:
WrapperClass代码
public class WrapperClass:NSObject, NSCoding, NSSecureCoding { public static var supportsSecureCoding: Bool = true var attributedStrings = [TextDocumentClass]() init(pAttributedStrings:[TextDocumentClass]) { self.attributedStrings = pAttributedStrings } required public init?(coder aDecoder: NSCoder){ self.attributedStrings = aDecoder.decodeObject(of: [TextDocumentClass.self], forKey: "attributedStrings") as? [TextDocumentClass] //return self } public func encode(with aCoder: NSCoder) { aCoder.encode(attributedStrings,forKey:"attributedStrings") } }
自定义ValueTransformer代码
@objc(MyTestClassValueTransformer) final class MyClassValueTransformer: NSSecureUnarchiveFromDataTransformer { static let name = NSValueTransformerName(rawValue: String(describing: MyClassValueTransformer.self)) public static func register() { let transformer = MyClassValueTransformer() ValueTransformer.setValueTransformer(transformer, forName: name) } override static var allowedTopLevelClasses: [AnyClass] { return super.allowedTopLevelClasses + [WrapperClass.self, UIFont.self, NSObject.self, NSParagraphStyle.self] } override public class func transformedValueClass() -> AnyClass { return WrapperClass.self } override public class func allowsReverseTransformation() -> Bool { return true } override public func transformedValue(_ value: Any?) -> Any? { guard let data = value as? Data else { return nil } do { let box = try NSKeyedUnarchiver.unarchivedObject( ofClass: WrapperClass.self, from: data ) return box } catch { return nil } } override public func reverseTransformedValue(_ value: Any?) -> Any? { guard let box = value as? WrapperClass else { return nil } do { let data = try NSKeyedArchiver.archivedData( withRootObject: box, requiringSecureCoding: true ) return data } catch { return nil } } }
TextDocumentClass代码
public class TextDocumentClass:NSObject, NSCoding, NSSecureCoding { public static var supportsSecureCoding: Bool = true var attributedText: NSAttributedString! var uuid:String! var isDeleted:Bool! var isChanged:Bool! var prevPageUUID:String! var nextPageUUID:String! var order:Int! var lastUpdatedDate:String! var isPDF: Bool! var pdfURL: String! var pdfPageNumber: Int! init (pAttributedText:NSAttributedString, pUUID:String, pPrevPageUUID:String, pNextPageUID:String, pOrder:Int, pIsDeleted: Bool, pIsChanged: Bool, pLastUpdatedDate: String, isPDF: Bool = false, pdfURL: String = "", pdfPageNumber: Int = -1) { self.attributedText = pAttributedText self.uuid = pUUID self.isDeleted = pIsDeleted self.isChanged = pIsChanged self.prevPageUUID = pPrevPageUUID self.nextPageUUID = pNextPageUID self.order = pOrder self.lastUpdatedDate = pLastUpdatedDate self.isPDF = isPDF self.pdfURL = pdfURL self.pdfPageNumber = pdfPageNumber } required public init?(coder aDecoder: NSCoder){ self.attributedText = (aDecoder.decodeObject(of: NSAttributedString.self, forKey: "attributedText"))! self.prevPageUUID = (aDecoder.decodeObject(of: NSString.self, forKey: "prevPageUUID") as? String)! self.nextPageUUID = (aDecoder.decodeObject(of: NSString.self, forKey: "nextPageUUID") as? String)! self.uuid = (aDecoder.decodeObject(of: NSString.self, forKey: "uuid") as? String)! self.isChanged = (aDecoder.decodeObject(of: NSNumber.self, forKey: "isChanged")?.boolValue)! self.isDeleted = (aDecoder.decodeObject(of: NSNumber.self, forKey: "isDeleted")?.boolValue)! self.order = (aDecoder.decodeObject(of: NSNumber.self, forKey: "order")?.intValue)! self.lastUpdatedDate = (aDecoder.decodeObject(of: NSString.self, forKey: "lastUpdatedDate") as? String)! self.isPDF = aDecoder.decodeObject(of: NSNumber.self, forKey: "isPDF")?.boolValue ?? false self.pdfURL = (aDecoder.decodeObject(of: NSString.self, forKey: "pdfURL") as? String ?? "") self.pdfPageNumber = aDecoder.decodeObject(of: NSNumber.self, forKey: "PDFpageNumber")?.intValue ?? -1 } public func encode(with aCoder: NSCoder) { aCoder.encode(attributedText,forKey:"attributedText") aCoder.encode(prevPageUUID,forKey:"prevPageUUID") aCoder.encode(nextPageUUID,forKey:"nextPageUUID") aCoder.encode(uuid,forKey:"uuid") aCoder.encode(isChanged,forKey:"isChanged") aCoder.encode(isDeleted,forKey:"isDeleted") aCoder.encode(order,forKey:"order") aCoder.encode(lastUpdatedDate,forKey:"lastUpdatedDate") aCoder.encode(isPDF, forKey: "isPDF") aCoder.encode(pdfURL, forKey: "pdfURL") aCoder.encode(pdfPageNumber, forKey: "PDFpageNumber") } override public init() { self.attributedText = NSAttributedString() self.uuid = "" self.isDeleted = false self.isChanged = false self.prevPageUUID = "" self.nextPageUUID = "" self.order = -1 self.lastUpdatedDate = "" self.isPDF = false self.pdfURL = "" self.pdfPageNumber = -1 } }
错误日志
//此代码行 let temp = try aDecoder.decodeTopLevelObject(of: [BaselineClass.self], forKey: "attributedStrings") //控制台输出如下 Allowed classes are: {( "'demo.BaselineClass' (0x100f6fc40) [/private/var/containers/Bundle/Application/EF7BF8EB-A98B-4B52-AE8F-1FB05F31ECC3/demo.app]" )}" UserInfo={NSDebugDescription=value for key 'attributedStrings' was of unexpected class 'NSArray' (0x1fc4b89e0) [/System/Library/Frameworks/CoreFoundation.framework]. Allowed classes are: {( "'demo.BaselineClass' (0x100f6fc40) [/private/var/containers/Bundle/Application/EF7BF8EB-A98B-4B52-AE8F-1FB05F31ECC3/demo.app]" )}} //若修改为如下代码 let temp = try aDecoder.decodeTopLevelObject(of: NSArray.self, forKey: "attributedStrings") //控制台输出变为 Allowed classes are: {( "'NSArray' (0x1fc4b89e0) [/System/Library/Frameworks/CoreFoundation.framework]" )}" UserInfo={NSDebugDescription=value for key 'NS.objects' was of unexpected class 'demo.BaselineClass' (0x103363c40) [/private/var/containers/Bundle/Application/1E080145-14D1-4D03-9520-E87C39B8F2C7/demo.app]. Allowed classes are: {( "'NSArray' (0x1fc4b89e0) [/System/Library/Frameworks/CoreFoundation.framework]" )}}
解决方案
- 修正数组解码的允许类:在
WrapperClass的init?(coder:)方法中,解码数组时需要同时指定数组类和元素类,因为存储的是NSArray类型的数组,元素是TextDocumentClass,所以修改解码代码为:self.attributedStrings = aDecoder.decodeObject(of: [NSArray.self, TextDocumentClass.self], forKey: "attributedStrings") as? [TextDocumentClass] - 更新ValueTransformer的允许类:在
MyClassValueTransformer的allowedTopLevelClasses中添加TextDocumentClass.self,确保嵌套的元素类被允许解码:override static var allowedTopLevelClasses: [AnyClass] { return super.allowedTopLevelClasses + [WrapperClass.self, TextDocumentClass.self, UIFont.self, NSParagraphStyle.self] } - 避免强制解包:
TextDocumentClass的解码方法中存在大量强制解包(!),一旦解码失败会直接崩溃,建议替换为可选绑定或默认值,例如:if let attributedText = aDecoder.decodeObject(of: NSAttributedString.self, forKey: "attributedText") { self.attributedText = attributedText } else { self.attributedText = NSAttributedString() }
内容的提问来源于stack exchange,提问作者Thomas Wix
相关产品推荐
相关产品推荐

