You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 21:21:48