核心数据中的 NSSecureCoding 崩溃

NSSecureCoding crash in Core Data

当我使用获取请求从我的核心数据实体获取时,我收到了用户的崩溃报告。这是崩溃的样子:

SIGABRT: Unhandled error (NSCocoaErrorDomain, 4864) occurred during faulting and was thrown: Error Domain=NSCocoaErrorDomain Code=4864 "The data couldn’t be read because it isn’t in the correct format." UserInfo={NSUnderlyingError=0x2822582d0 {Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'NS.objects' was of unexpected class 'NSTextAlternatives (0x1ffa90890) [/System/Library/PrivateFrameworks/UIFoundation.framework]'. Allowed classes are '{( "NSTextAttachment (0x1ff3bc730) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSNumber (0x1ff35d8c8) [/System/Library/Frameworks/Foundation.framework]", "NSDictionary (0x1ff352418) [/System/Library/Frameworks/CoreFoundation.framework]", "NSFont (0x1ff3bc3e8) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSGlyphInfo (0x1ffa906d8) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSArray (0x1ff352238) [/System/Library/Frameworks/CoreFoundation.framework]", "NSParagraphStyle (0x1ff3bbec0) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSUUID (0x1ff35f290) [/System/Library/Frameworks/Foundation.framework]", "NSDate (0x1ff3522b0) [/System/Library/Frameworks/CoreFoundation.framework]", "NSColor (0x1ff3a67a8) [/System/Library/PrivateFrameworks/UIKitCore.framework]", "NSNull (0x1ff3527b0) [/System/Library/Frameworks/CoreFoundation.framework]", "NSData (0x1ff3519c8) [/System/Library/Frameworks/CoreFoundation.framework]", "UIColor (0x1ff3a6a78) [/System/Library/PrivateFrameworks/UIKitCore.framework]", "NSAttributedString (0x1ff359c00) [/System/Library/Frameworks/Foundation.framework]", "NSURL (0x1ff352e18) [/System/Library/Frameworks/CoreFoundation.framework]", "NSSet (0x1ff352878) [/System/Library/Frameworks/CoreFoundation.framework]", "NSValue (0x1ff35d940) [/System/Library/Frameworks/Foundation.framework]", "UIFont (0x1ff3bc780) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSString (0x1ff35d170) [/System/Library/Frameworks/Foundation.framework]" )}'." UserInfo={NSDebugDescription=value for key 'NS.objects' was of unexpected class 'NSTextAlternatives (0x1ffa90890) [/System/Library/PrivateFrameworks/UIFoundation.framework]'. Allowed classes are '{( "NSTextAttachment (0x1ff3bc730) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSNumber (0x1ff35d8c8) [/System/Library/Frameworks/Foundation.framework]", "NSDictionary (0x1ff352418) [/System/Library/Frameworks/CoreFoundation.framework]", "NSFont (0x1ff3bc3e8) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSGlyphInfo (0x1ffa906d8) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSArray (0x1ff352238) [/System/Library/Frameworks/CoreFoundation.framework]", "NSParagraphStyle (0x1ff3bbec0) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSUUID (0x1ff35f290) [/System/Library/Frameworks/Foundation.framework]", "NSDate (0x1ff3522b0) [/System/Library/Frameworks/CoreFoundation.framework]", "NSColor (0x1ff3a67a8) [/System/Library/PrivateFrameworks/UIKitCore.framework]", "NSNull (0x1ff3527b0) [/System/Library/Frameworks/CoreFoundation.framework]", "NSData (0x1ff3519c8) [/System/Library/Frameworks/CoreFoundation.framework]", "UIColor (0x1ff3a6a78) [/System/Library/PrivateFrameworks/UIKitCore.framework]", "NSAttributedString (0x1ff359c00) [/System/Library/Frameworks/Foundation.framework]", "NSURL (0x1ff352e18) [/System/Library/Frameworks/CoreFoundation.framework]", "NSSet (0x1ff352878) [/System/Library/Frameworks/CoreFoundation.framework]", "NSValue (0x1ff35d940) [/System/Library/Frameworks/Foundation.framework]", "UIFont (0x1ff3bc780) [/System/Library/PrivateFrameworks/UIFoundation.framework]", "NSString (0x1ff35d170) [/System/Library/Frameworks/Foundation.framework]" )}'.}}}CrashVersion 5.6.8 (5.6.9)1 user1 report

NSFetchedResultsController 调用 performFetch:

时崩溃的行

7 CoreData 0x00000001b48c1a94 __43-[NSFetchedResultsController performFetch:]_block_invoke + 572 8 CoreData 0x00000001b487c01c developerSubmittedBlockToNSManagedObjectContextPerform + 152 9
CoreData 0x00000001b474eda4 -[NSManagedObjectContext performBlockAndWait:] + 204 10 CoreData 0x00000001b475cae4 -[NSFetchedResultsController _recursivePerformBlockAndWait:withContext:] + 144 11 CoreData 0x00000001b475cc1c -[NSFetchedResultsController performFetch:] + 220

这几乎肯定会发生,因为我最近将一个没有任何转换器集的可转换属性(因此基本上使用 NSKeyedUnarchiveFromDataTransformerName)更改为使用 NSSecureUnarchiveFromDataTransformer 的子 class .该属性正在存储来自 iOS 应用程序中的 UITextViewNSAttributedString。我还将 'bold' 和 'italics' 项目的 NSRange 保存为 NSValue。

我添加了以下转换器:

@objc(AttributedStringDictionaryTransformer)
final class AttributedStringDictionaryTransformer: NSSecureUnarchiveFromDataTransformer {

    override static var allowedTopLevelClasses: [AnyClass] {
        return super.allowedTopLevelClasses + [NSValue.self]
    }
}

这个'transformer'用于核心数据模型中的Transformable属性。它将 NSValue class 添加到 classes.

的允许列表中

当它说“键 'NS.objects' 的值是意外的 class 'NSTextAlternatives”时......我不确定 NSTextAlternatives 是什么。我从来没有(明确地)在我的代码中使用过它。任何想法可能来自哪里?

编辑: 在进一步调查中,事实证明 NSAttributedString 可以附加各种对象,例如 NSTextAlternatives_UITextInputDictationResultMetadata 的对象,如果用户在 UITextView 上使用听写,这些对象可能会出现。所以技术上支持 NSAttributedString 的 NSSecureUnarchiveFromDataTransformer 实际上并没有正确支持它。这些 classes 来自私有框架,所以不确定如何将它们添加到我的自定义转换器中。除了提交错误外,不确定是否有其他解决方法。如果有,请告诉我。

事实上,NSAttributedString 可能有点像文本系统相关属性的抓包:文本视图中的各种操作可能导致文本系统(CoreText、UIKit 等)注释范围使用一些元数据来改善 iOS 体验,但这确实意味着任何给定的 NSAttributedString 最终都会带来一些您可能没有意识到的包袱。 (从概念上讲,NSAttributedString 就像一个 NSString 和一个关联的 NSDictionary,它可以包含 任何东西 ,如果你斜眼看的话。)文本的常规使用视图可能会导致这种情况,当您也考虑从 other 属性字符串源粘贴文本时,您最终可能会得到许多您不期望的属性值。这是按预期工作的文本系统。

不幸的是,这种设计与 NSSecureCoding 相冲突,后者要求您在解码之前列出您希望从存档中解码的类型。你正确地将 NSAttributedStringNSValue 对象列入白名单,并且 NSAttributedString 本身将它知道的几种类型列入白名单(并且 NSSecureUnarchiveFromDataTransformer 也允许一些已知的 Foundation 类型),但是问题是字符串最终包含 neithernor NSAttributedString 知道的类型,并且如果不将这些列入白名单,解码将被阻止。

由于这些类型确实是私有的,您将很难找到文本系统可能抛给您的所有可能的私有类型。最简单的方法是在 encoding 方面:在对 NSAttributedString 进行编码之前,遍历其所有属性范围并删除类型不符合您的任何属性白名单标准。在编码时使用与解码时相同的标准将使您能够成功解码。