基础序列化
本页介绍 Fory Swift 默认 xlang 模式下的对象图序列化和核心 API 用法。
对象图序列化
使用 @ForyStruct、@ForyEnum 或 @ForyUnion,注册类型,然后进行序列化和反序列化。
import Foundation
import Fory
@ForyStruct
struct Address: Equatable {
var street: String = ""
var zip: Int32 = 0
}
@ForyStruct
struct Person: Equatable {
var id: Int64 = 0
var name: String = ""
var nickname: String? = nil
var tags: Set<String> = []
var scores: [Int32] = []
var addresses: [Address] = []
var metadata: [Int8: Int32?] = [:]
}
let fory = Fory()
try fory.register(Address.self, id: 100)
try fory.register(Person.self, id: 101)
let person = Person(
id: 42,
name: "Alice",
nickname: nil,
tags: ["swift", "xlang"],
scores: [10, 20, 30],
addresses: [Address(street: "Main", zip: 94107)],
metadata: [1: 100, 2: nil]
)
let data = try fory.serialize(person)
let decoded: Person = try fory.deserialize(data)
assert(decoded == person)
使用现有缓冲区
将序列化字节追加到现有 Data,并从 ByteBuffer 反序列化。
var output = Data()
try fory.serialize(person, to: &output)
let inputBuffer = ByteBuffer(data: output)
let fromBuffer: Person = try fory.deserialize(from: inputBuffer)
assert(fromBuffer == person)
选择序列化器
实现 Serializer 且 Target == Self 的类型会选择自身:
let data = try fory.serialize(person)
let decoded: Person = try fory.deserialize(data)
这种隐式选择可以通过生成字段和普通 optional、array、set、dictionary 组合。当应用有意 让外部类型追溯遵循以自身为目标的协议时,也适用此规则。
当单独的序列化器以该值为目标时,使用 with 选择它:
try fory.register(UserSerializer.self, id: 200)
let data = try fory.serialize(
externalUser,
with: UserSerializer.self
)
let decoded = try fory.deserialize(
data,
with: UserSerializer.self
)
同样的选择也适用于现有缓冲区:
var output = Data()
try fory.serialize(
externalUser,
with: UserSerializer.self,
to: &output
)
let input = ByteBuffer(data: output)
let decoded = try fory.deserialize(
from: input,
with: UserSerializer.self
)
外部结构化序列化器和递归载体根值请参阅外部类型序列化。由类型直接实现 的序列化器、追溯遵循和单独的自定义序列化器请参阅 自定义序列化器。
内置支持的类型
基本类型和标量
BoolInt8,Int16,Int32,Int64,IntUInt8,UInt16,UInt32,UInt64,UIntFloat,DoubleStringData
日期和时间
DateLocalDateDuration
时间戳值使用 Date,只包含日期的值使用 LocalDate。LocalDate 支持纪元日转换和 Date
转换,可使用 fromEpochDay(_:)、toEpochDay()、init(utcDate:) 和 toUTCDate()。
集合
- 值直接实现
Serializer的 optional 和 array - 元素直接实现
Serializer且为Hashable的 set - 键和值直接实现
Serializer,且键为Hashable的 dictionary
使用单独序列化器的子项通过以下类型组合:
OptionalSerializer<S>ArraySerializer<S>SetSerializer<S>DictionarySerializer<KS, VS>
动态类型
Any和AnyObjectAnyHashable- 任意应用 protocol 值
- 受支持的异构 array 和 dictionary
Any 和 AnyObject 根值使用直接根值 API。任意应用 protocol 根值和嵌套在载体中的动态值
使用显式 with: 选择。请参阅多态和动态类型。
跨语言互操作
以下内容说明默认 xlang 格式的跨语言类型映射、类型标识和互操作要求。
Fory Swift 可以使用 xlang 协议与其他 Fory 实现交换载荷。
推荐的 Xlang 配置
let fory = Fory()
使用共享标识注册类型
基于 ID 的注册
@ForyStruct
struct Order {
var id: Int64 = 0
var amount: Double = 0
}
let fory = Fory()
try fory.register(Order.self, id: 100)
基于名称的注册
try fory.register(Order.self, name: "com.example.Order")
Xlang 规则
- 在不同语言间保持类型注册映射一致
- 独立演进 Schema 时保持启用兼容模式。Swift 默认启用兼容模式。
- 注册动态字段和应用 protocol 值所使用的所有用户定义具体目标
- 对其他模块拥有的类型,使用外部结构化序列化器、单独的自定义序列化器,或一个有意添加的 追溯自目标遵循
List 和密集数组
Swift Array<T> 字段映射为 Fory list<T>,除非字段元数据显式请求密集 array<T>。
array<T> 只用于一维 bool 或数值数据。
| Fory Schema | Swift 字段元数据示意 |
|---|---|
list<int32> | @ListField(element: .int32()) var ids: [Int32] |
array<bool> | @ArrayField(element: .bool) var flags: [Bool] |
array<int8> | @ArrayField(element: .int8) var values: [Int8] |
array<int16> | @ArrayField(element: .int16) var values: [Int16] |
array<int32> | @ArrayField(element: .int32()) var values: [Int32] |
array<int64> | @ArrayField(element: .int64()) var values: [Int64] |
array<uint8> | @ArrayField(element: .uint8) var values: [UInt8] |
array<uint16> | @ArrayField(element: .uint16) var values: [UInt16] |
array<uint32> | @ArrayField(element: .uint32()) var values: [UInt32] |
array<uint64> | @ArrayField(element: .uint64()) var values: [UInt64] |
array<float16> | @ArrayField(element: .float16) var values: [Float16] |
array<bfloat16> | @ArrayField(element: .bfloat16) var values: [BFloat16] |
array<float32> | @ArrayField(element: .float32) var values: [Float] |
array<float64> | @ArrayField(element: .float64) var values: [Double] |
使用单独元素序列化器的 array 仍使用普通 list 编码。只对受支持的密集 bool 或数值数组使用
@ArrayField。
外部目标
外部结构化序列化器生成的 xlang STRUCT、ENUM 或 UNION Schema 和值字节,与等效普通 Swift 模型相同:
@ForyStruct(target: ThirdParty.Order.self)
struct OrderSerializer {
var id: Int64
var amount: Double
}
try fory.register(OrderSerializer.self, id: 100)
在字段元数据中使用 .with(...),在根值处使用 with:。请参阅
外部类型序列化。
由于结构化序列化器是单独声明,因此必须显式选择。相反,如果外部类型有一个有意添加的
追溯 Target == Self 遵循,则使用普通根值、字段和载体。
Swift 没有原生序列化模式。已知 @ForyUnion case 包含零个或一个关联值。如果 union 候选项
包含多个逻辑字段,请使用 struct 载荷。
Swift IDL 工作流
直接从 Fory IDL/Proto/FBS 输入生成 Swift 模型:
foryc schema.fdl --swift_out ./Sources/Generated
生成的 Swift 代码包括:
@ForyStruct、@ForyEnum、@ForyUnion以及字段/case 元数据- Tagged union enum(关联值 enum case)
- 支持传递安装 import 的
ForyModule.install(_:)辅助方法 - 生成类型上的
toBytes/fromBytes辅助方法
进行 xlang 序列化前安装生成模块:
let fory = Fory(ref: true)
try Addressbook.ForyModule.install(fory)
let payload = try fory.serialize(book)
let decoded: Addressbook.AddressBook = try fory.deserialize(payload)
运行 Swift IDL 集成测试
cd integration_tests/idl_tests
./run_swift_tests.sh
该命令运行 Swift 往返矩阵测试和 Java 对等端往返检查(IDL_PEER_LANG=swift)。
调试 Xlang 测试
运行 xlang 测试时启用调试输出:
ENABLE_FORY_DEBUG_OUTPUT=1 FORY_SWIFT_JAVA_CI=1 mvn -T16 test -Dtest=org.apache.fory.xlang.SwiftXlangTest
首次往返
import Fory
@ForyStruct
struct Person: Equatable {
var name: String = ""
var age: Int32 = 0
}
let fory = Fory()
fory.register(Person.self, id: 1)
let person = Person(name: "chaokunyang", age: 28)
let data = try fory.serialize(person)
let result: Person = try fory.deserialize(data)
print("\(result.name) \(result.age)")
更多跨语言规则和示例请参阅: