0

我存档了一个NSAttributedString,其中包含NSTextAttachment在 iOS14 上的图像,并注意到在 iOS13 上取消存档失败。在 iOS14 上,解压成功。

记录的错误是这样的:

Error decoding string object. error=Error Domain=NSCocoaErrorDomain Code=4864 
"value for key 'NS.objects' was of unexpected class 'NSTextAttachment'. Allowed classes are '{(
    NSGlyphInfo,
    UIColor,
    NSURL,
    UIFont,
    NSParagraphStyle,
    NSString,
    NSAttributedString,
    NSArray,
    NSNumber,
    NSDictionary
)}'." UserInfo={NSDebugDescription=value for key 'NS.objects' was of unexpected class 'NSTextAttachment'. Allowed classes are '{(
    NSGlyphInfo,
    UIColor,
    NSURL,
    UIFont,
    NSParagraphStyle,
    NSString,
    NSAttributedString,
    NSArray,
    NSNumber,
    NSDictionary
)}'.}

有没有办法让它发挥作用,还是我注定要在这里?

这是将图像插入NSMutableAttributedStringusing的方式NSTextAttachment

// Add an image:
NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
textAttachment.image = image;
NSMutableAttributedString *strWithImage = [[NSAttributedString attributedStringWithAttachment:textAttachment] mutableCopy];

[s appendAttributedString:strWithImage];

这是归档行:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:str requiringSecureCoding:YES error:&error];

这是取消归档的行,它返回一个NSError实例:

NSError *error = nil;
NSAttributedString *str = [NSKeyedUnarchiver unarchivedObjectOfClass:NSAttributedString.class fromData:data error:&error];

NSData在 iOS14 上创建实例,将其存储到文件中并在 iOS13 中读取。这是它失败的时候。

4

2 回答 2

1

该错误清楚地表明NSTextAttachment无法解码,因为它不在受支持的类列表中。

您必须找到一种解决方法才能使其在 iOS 13 或更低版本上运行。

可能的解决方案

  1. NSMutableAttributedString实例中删除所有附件。
  2. archive这和你今天做的一样。
  3. [TextAttachmentInfo]对与上述数据配对的 JSON 数据进行编码和存储。
  4. unarchive这和你今天做的一样。
  5. 将配对的 JSON 数据解码为[TextAttachmentInfo].
  6. NSTextAttachments 插入未归档的NSMutableAttributedString实例中

这是一些需要根据您自己的用例进一步调整和测试的帮助代码。

extension NSMutableAttributedString {
    
    struct TextAttachmentInfo: Codable {
        let location: Int
        let imageData: Data
    }
    
    func removeAllTextAttachments() -> [TextAttachmentInfo] {
        guard self.length > 0 else { return [] }
        
        var textAttachmentInfos: [TextAttachmentInfo] = []
        
        for location in (0..<self.length).reversed() {
            var effectiveRange = NSRange()
            let attributes = self.attributes(at: location, effectiveRange: &effectiveRange)
            
            for (_, value) in attributes {
                if let textAttachment = value as? NSTextAttachment,
                   let data = textAttachment.image?.pngData() {
                    self.replaceCharacters(in: effectiveRange, with: "")
                    textAttachmentInfos.append(.init(location: effectiveRange.location, imageData: data))
                }
            }
        }
        
        return textAttachmentInfos.reversed()
    }
    
    func insertTextAttachmentInfos(_ infos: [TextAttachmentInfo]) {
        for info in infos {
            let attachment = NSTextAttachment()
            attachment.image = UIImage(data: info.imageData)
            self.insert(NSAttributedString(attachment: attachment), at: info.location)
        }
    }
    
}
于 2021-06-01T20:23:52.557 回答
0

我的一个解决方案是在initWithCoder:包含NSAttributedString. (感谢 Markus Spoettl 在几年前的 cocoa-dev 邮件列表中提供的解决方案。)

-(instancetype)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        NSAttributedString *str = nil;
        // This fails on iOS13:
        // str = [coder decodeObjectOfClass:NSAttributedString.class forKey:@"attrStr"];

        // Provide a set of classes to make NSTextAttachment accepted:
        str = [coder decodeObjectOfClasses:[NSSet setWithObjects:
            NSAttributedString.class, 
            NSTextAttachment.class, nil] forKey:@"attrStr"];
        self.attrStr = str;
    }
    return self;
}

这似乎是与NSAttributedStringtoo likeNSTextTab等一起使用的其他类的问题。因此,根据用例,可以扩展可接受的类列表。

于 2021-06-02T18:16:27.650 回答