| title | Polymorphism and Dynamic Types |
|---|---|
| sidebar_position | 9 |
| id | polymorphism |
| license | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |
Fory Swift supports dynamic serialization for Any, AnyObject, arbitrary
application protocol existentials, and supported heterogeneous collections.
Any and AnyObject roots use direct convenience APIs. Application protocols
and recursively composed carriers select DynamicSerializer explicitly.
let fory = Fory()
let dynamic: Any = Int32(7)
let data = try fory.serialize(dynamic)
let decoded: Any = try fory.deserialize(data)The equivalent explicit form is
with: DynamicSerializer<Any>.self. It is useful when composing serializers,
but is unnecessary for an Any root. AnyObject has the same direct root
APIs.
A concrete external value passed as Any may use its registered serializer.
For typed roots and fields, select a separate serializer explicitly with
with:.
Heterogeneous containers compose carrier serializers:
typealias AnyArraySerializer =
ArraySerializer<DynamicSerializer<Any>>
typealias StringAnyMapSerializer = DictionarySerializer<
String,
DynamicSerializer<Any>
>Use DynamicSerializer<AnyHashable> for an erased dynamic dictionary key.
Use the exact heterogeneous shape for dynamic lists and maps: [Any],
[String: Any], [Int32: Any], or [AnyHashable: Any]. For example, write
["a", "b"] as [Any] before storing that heterogeneous list in Any.
Keep homogeneous lists and maps in their ordinary concrete types.
Register each concrete target that may appear. No Fory-specific marker protocol is required:
protocol Animal {
var name: String { get }
}
@ForyStruct
struct Dog: Animal {
var name: String = ""
}
@ForyStruct(target: ThirdParty.Cat.self)
struct CatSerializer {
var name: String
}
let fory = Fory()
try fory.register(Dog.self, id: 100)
try fory.register(CatSerializer.self, id: 101)
let input: any Animal = Dog(name: "Rex")
let data = try fory.serialize(
input,
with: DynamicSerializer<any Animal>.self
)
let output = try fory.deserialize(
data,
with: DynamicSerializer<any Animal>.self
)Every concrete target must conform to the requested application protocol. A target that is unregistered or does not conform fails deserialization.
Application protocol fields are dynamic:
@ForyStruct
struct Zoo {
var featured: any Animal
var animals: [any Animal]
}Register Zoo and every concrete target that may appear.
Use an optional when the field needs a nil default:
@ForyStruct
struct OptionalZoo {
var featured: (any Animal)? = nil
}Use DynamicSerializer<T> as the child of a root carrier:
typealias AnimalArraySerializer =
ArraySerializer<DynamicSerializer<any Animal>>
let data = try fory.serialize(
animals,
with: AnimalArraySerializer.self
)
let decoded = try fory.deserialize(
data,
with: AnimalArraySerializer.self
)Optional and map roots compose the same way:
typealias FeaturedSerializer =
OptionalSerializer<DynamicSerializer<any Animal>>
typealias AnimalMapSerializer = DictionarySerializer<
String,
DynamicSerializer<any Animal>
>Swift's normal Hashable rules still apply to set elements and dictionary
keys. Use AnyHashable for erased dynamic keys.
Select DynamicSerializer<Base> when a class-typed field must preserve its
concrete subclass:
@ForyField(with: DynamicSerializer<AnimalBase>.self)
var animal: AnimalBaseRegister every concrete subclass that may appear.
@ForyStruct
struct DynamicHolder {
var value: Any = ForyAnyNullValue()
var list: [Any] = []
var byName: [String: Any] = [:]
var byId: [Int32: Any] = [:]
var byDynamicKey: [AnyHashable: Any] = [:]
}If dynamic values contain user-defined types, register those concrete types.
@ForyStruct
struct Address {
var street: String = ""
var zip: Int32 = 0
}
let fory = Fory()
try fory.register(Address.self, id: 100)Anynull representation:ForyAnyNullValueAnyObjectnull representation:NSNullAnyHashabledynamic null-key representation:AnyHashable(ForyAnyNullValue())- Optional dynamic values map to the corresponding null representation on decode
AnyHashable keys must wrap values that are both Hashable and supported by
Fory dynamic serialization.