【问题标题】:NSSecureCoding crash in Core Data核心数据中的 NSSecureCoding 崩溃
【发布时间】:2021-06-03 18:41:20
【问题描述】:

当我使用 fetch 请求从我的 Core Data 实体中获取数据时,我收到了来自用户的崩溃报告。这是崩溃的样子:

SIGABRT:未处理的错误(NSCocoaErrorDomain,4864)发生在 出错并被抛出:错误域 = NSCocoaErrorDomain 代码 = 4864 “无法读取数据,因为它的格式不正确。” UserInfo={NSUnderlyingError=0x2822582d0 {错误 Domain=NSCocoaErrorDomain Code=4864 "键 'NS.objects' 的值是 意外的类 'NSTextAlternatives (0x1ffa90890) [/System/Library/PrivateFrameworks/UIFoundation.framework]'。允许 类是'{(“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=key 'NS.objects' 的值是 意外的类 'NSTextAlternatives (0x1ffa90890) [/System/Library/PrivateFrameworks/UIFoundation.framework]'。允许 类是'{(“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 报告

NSFetchedResultsController 调用performFetch 时,它崩溃的那一行:

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

这几乎肯定会发生,因为我最近将没有任何转换器集的 Transformable 属性(因此基本上使用NSKeyedUnarchiveFromDataTransformerName)更改为使用NSSecureUnarchiveFromDataTransformer 的子类。该属性存储来自 iOS 应用程序中的UITextViewNSAttributedString。我还将“粗体”和“斜体”项目的 NSRange 保存为 NSValue。

我添加了以下转换器:

@objc(AttributedStringDictionaryTransformer)
final class AttributedStringDictionaryTransformer: NSSecureUnarchiveFromDataTransformer {

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

此“转换器”用于核心数据模型中的可转换属性。它将NSValue 类添加到允许的类列表中。

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

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

【问题讨论】:

    标签: objective-c core-data nsvalue nsvaluetransformer nssecurecoding


    【解决方案1】:

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

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

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

    【讨论】:

    • 这是用于生产中的现有应用程序,它已经直接从 UITextView 保存了属性文本。我想的临时解决方案是暂时回到使用NSKeyedUnarchiveFromDataTransformerName,然后在使用NSSecureUnarchiveFromDataTransformer之前进行一些处理以从NSAttributedString中去除所有这些私有属性。
    • @ZS 是的,您需要一个数据迁移策略。您可能需要一个(或几个)继续使用非安全转换器的构建,但通过剥离属性并重新保存来向前迁移数据。或者,如果保存的数据以任何方式进行版本控制,您可以在加载时向前迁移旧数据版本。主要问题是应用程序的新旧版本之间的互操作(如果适用)。
    猜你喜欢
    • 1970-01-01
    • 2014-11-09
    • 2023-03-14
    • 2018-09-02
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    相关资源
    最近更新 更多