To avoid data races, the internal Registry singleton has been removed, instead preferring an explicit user-defined Registry. For example, when parsing or querying units from Strings, a registry instance should be passed:
let meter = try Unit(fromSymbol: "m") // old
let meter = try Unit(fromSymbol: "m", registry: registry) // newNote that if registry is omitted from these functions, the default unit database is used, which should provide a relatively smooth transition in the common case where custom units are not used.
Registries should be defined and instantiated during startup, and must not be changed after creation. To enforce this lifecycle, a RegistryBuilder has been introduced that custom units may be registered to.
// old
let centifoot = try Unit.define(
name: "centifoot",
symbol: "cft",
dimension: [.Length: 1],
coefficient: 0.003048
)
// new
let registryBuilder = RegistryBuilder()
registryBuilder.addUnit(
name: "centifoot",
symbol: "cft",
dimension: [.Length: 1],
coefficient: 0.003048
)
let registry = registryBuilder.registry()To provide Registry lookup support inside Encode/Decode processes, a userInfo key has been added:
let encoder = JSONEncoder()
encoder.userInfo[Unit.registryUserInfoKey] = Registry.default
try encoder.encode(Unit.meter / .second)
let decoder = JSONDecoder()
decoder.userInfo[Unit.registryUserInfoKey] = Registry.default
try decoder.decode(Unit.self, from: "\"m\\/s\"".data(using: .utf8)!)