问题描述
我在 iOS14 上归档了一个 NSAttributedString
,其中包含一个带有 NSTextAttachment
的图像,并注意到在 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,NSDictionary
)}'.}
有没有办法让它发挥作用,还是我注定要在这里?
这是使用 NSMutableAttributedString
将图像插入到 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];
我在 iOS14 上创建了 NSData
实例,将它存储到一个文件中并在 iOS13 中读取它。这是它失败的时候。
解决方法
错误明确指出 NSTextAttachment
无法解码,因为它不在支持的类列表中。
您必须找到一种解决方法才能使其在 iOS 13 或更低版本上运行。
可能的解决方案
- 从
NSMutableAttributedString
实例中删除所有附件。 -
archive
就像你今天所做的一样。 - 编码并存储与上述数据配对的
[TextAttachmentInfo]
JSON 数据。 -
unarchive
就像你今天所做的一样。 - 将配对的 JSON 数据解码为
[TextAttachmentInfo]
。 - 将
NSTextAttachment
插入未归档的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)
}
}
}
,
对我来说,一个解决方案是在包含 await db
.collection('users')
.doc(user.email)
.collection('starred')
.doc(user.id)
.set({ set: true });
的类的 initWithCoder:
方法中提供可接受类的列表。 (版权归于 Markus Spoettl 几年前在 cocoa-dev 邮件列表中的解决方案。)
NSAttributedString
这似乎是与 -(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;
}
一起使用的其他类的问题,例如 NSAttributedString
等,因此根据用例,可以扩展可接受的类列表。