Swift 5.5自定义AttributedString属性JSON编码异常问题求助
Swift 5.5 Codable AttributedString 自定义属性丢失及Font编码异常问题
问题现象
Swift 5.5 为AttributedString新增了Codable支持,但实际使用中遇到两个问题:
- 自定义的
TextCase属性在JSON编码时完全丢失 - 设置的
SwiftUI.Font.largeTitle编码后变成空对象{}
原始代码
自定义属性定义
public enum TextCase: Codable { case lowercase case uppercase } public struct TextCaseAttribute: CodableAttributedStringKey { public typealias Value = TextCase public static var name = "TextCaseAttribute" } public extension AttributeScopes { struct ExtendedTextAttributes: AttributeScope { public let textCase: TextCaseAttribute public let foundation: FoundationAttributes } var customAttributes: ExtendedTextAttributes.Type { ExtendedTextAttributes.self } } public extension AttributeDynamicLookup { subscript<T: AttributedStringKey>( dynamicMember keyPath: KeyPath<AttributeScopes.ExtendedTextAttributes, T> ) -> T { get { self[T.self] } } }
使用代码
var hello: AttributedString { var result = AttributedString("Hello") result.textCase = .uppercase result.font = .largeTitle return result }
编码结果
["Hello",{"SwiftUI.Font":{}}]
问题原因及解决方案
1. 自定义属性丢失原因
自定义CodableAttributedStringKey的属性范围没有被AttributedString正确识别。默认情况下,AttributedString使用基础属性范围,不会自动包含自定义扩展的属性范围,导致编码时忽略自定义属性。
解决方法:
直接为AttributedString扩展属性访问器,绕过动态查找的潜在问题,确保属性被正确关联到自定义键:
public extension AttributedString { var textCase: TextCase? { get { self[TextCaseAttribute.self] } set { self[TextCaseAttribute.self] = newValue } } }
同时确保自定义属性键的name唯一,避免与系统属性冲突。
2. SwiftUI.Font编码为空原因
SwiftUI.Font本身并未实现Codable协议,虽然AttributedString允许设置该类型,但底层无法将其序列化为JSON,最终输出空对象。
解决方法:
将SwiftUI.Font转换为平台原生字体类型(iOS的UIFont、macOS的NSFont)后再设置,原生字体类型支持Codable:
import SwiftUI import UIKit // iOS平台,macOS替换为AppKit.NSFont public extension AttributedString { mutating func setFont(_ swiftUIFont: Font) { self.font = UIFont(swiftUIFont) } }
修改后的完整代码
public enum TextCase: Codable { case lowercase case uppercase } public struct TextCaseAttribute: CodableAttributedStringKey { public typealias Value = TextCase public static var name = "TextCaseAttribute" } public extension AttributedString { var textCase: TextCase? { get { self[TextCaseAttribute.self] } set { self[TextCaseAttribute.self] = newValue } } } import SwiftUI import UIKit public extension AttributedString { mutating func setFont(_ swiftUIFont: Font) { self.font = UIFont(swiftUIFont) } } // 使用示例 var hello: AttributedString { var result = AttributedString("Hello") result.textCase = .uppercase result.setFont(.largeTitle) return result }
验证编码结果
此时编码后的JSON会包含自定义TextCaseAttribute和正确的字体信息,类似:
["Hello",{"TextCaseAttribute":"uppercase","NSFont":{"name":"SFProDisplay-Bold","pointSize":34}}]
内容的提问来源于stack exchange,提问作者Mosbah
相关产品推荐
相关产品推荐

