ModelKit 0.4.4

ModelKit 0.4.4

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2017年3月
SwiftSwift 版本3.0
SPM支持 SPM

Sam Williams 维护。



ModelKit 0.4.4

  • Sam Williams

ModelKit

这是一个用于处理模型对象的框架。

pod 'ModelKit'

或者,仅包括某些组件

  • ‘ModelKit/Fields’
  • 'ModelKit/Models’
  • 'ModelKit/RemoteModelStore’ (Alamofire 依赖)

字段

字段为您提供

  • 类型安全的变化观察
  • 自动时间戳
  • 验证

基本用法

class Person {
  let age = Field<Int>()
}
person.age.value = 10

对于多值字段,有 ArrayField,它封装了一个描述单值类型的字段对象。

let tags = ArrayField(Field<String>(), name: "Tags")

内部字段负责验证、转换等。 ArrayField 拥有顶级属性,如 namekey 等 - 但为了方便,它将在初始化时复制它们。

提供了一个一元后缀运算符 * 来将 Field 封装在 ArrayField 中。所以您也可以这样编写上面的声明

let tags = Field<String>(name: "Tags")*

验证

简单的闭包验证

let age = Field<Int>().require { $0 > 0 }

规则也可以链接,表示 AND。顺序并不重要。

let age = Field<Int>().require { $0 > 0 }.require { $0 % 2 == 0 }

默认情况下,nil 值将被视为有效。要更改特定规则的此行为,将 allowNil: false 传递给 require

要验证字段值,请调用 field.validate(),它返回一个 ValidationState 枚举

public enum ValidationState:Equatable {
    case unknown
    case invalid([String])
    case valid
}

.invalid 案例的相关值是一个错误信息列表(例如,["必须大于0","是必需的"])。

时间戳

字段将自动具有以下时间戳

  • updatedAt:最后一个设置任何值的时间
  • changedAt:最后设置新值的时间(使用 == 进行比较)

观察者

该库包括 ValueObserverValueObservable 协议,用于泛型、类型安全的变化观察。字段实现了这两个协议。

一个 ValueObservable 可以有任意数量的已注册 ValueObserver 对象。 --> 运算符是 addObserver 方法的一个快捷键(<-- 的作用相同,只是其参数的顺序相反)。当添加观察者时,观察事件会触发一次,之后每次设置字段值时都会触发。

添加观察者

如果观察者实现了ValueObserver协议,其中包含一个valueChanged(observable, value: value)方法,那么可以添加观察者。

field --> observer

或者,可以提供一个闭包。在不使用观察者对象的情况下,仅用owner来识别每个闭包。

field --> owner { value in
  print(value)
}

即使在没有给出观察者的情况下,我们仍然可以注册闭包。这实际上是在与空观察者注册闭包。

age --> { value in 
  print("Age was changed to \(value)")
}

将字段绑定到另一个字段

由于Field自身实现了ValueObservableValueObserver,可以使用-->运算符创建两个字段值之间的链接。

sourceField --> destinationField

这将立即设置destinationField的值为sourceField的值,并在sourceField的值每次发生变化时再次设置。

<-->运算符是紧随其后<---->的快捷方式(并且只能在两个字段之间使用)。

field1 <--> field2

由于首先调用<--,因此两个字段最初都将具有field2的值。

注销

注销观察者使用removeObserver方法,或者-/->运算符。可以用removeAllObservers()移除所有观察者。

模型

一个Model对象会自动将其Field属性的字典表示形式进行转换。

person.dictionaryValue()
// --> ["name": "Bob", "tags": ["red", "blue", "green"]]

如果你的字段的值是Model的子类,你应该使用ModelField子类。

let companies = ModelField<Company>()*

模型存储库

此库提供了一个基于Promise的数据存储抽象接口,该接口在ModelStore协议中指定,以及几个具体的实现。

func create<T: Model>(model:T) -> Promise<T>
func update<T: Model>(model:T) -> Promise<T>
func delete<T: Model>(model:T) -> Promise<T>
func lookup<T: Model>(modelClass:T.Type, identifier:String) -> Promise<T>
func list<T: Model>(modelClass:T.Type) -> Promise<[T]>

MemoryModelStore

这个存储库将模型存储在内存中。它为基于同步的标识符查找添加了一个lookupImmediately方法。

RemoteModelStore

这旨在作为你RESTful服务器接口的基类。它包括一些可覆盖的钩子,你可以为了满足特定的需求自定义它们,例如

  • defaultHeaders
  • handleError
  • constructResponse

RESTRouter负责为资源位置生成路径。

collectionPath(for: Person.self)
instancePath(for: person)

如果你的模型符合HasOwnerField,则可以自动生成嵌套路由,这将要求它指定一个所属字段。例如,如果某人的所属字段是它的company字段,那么你可能得到它的实例路径为"/companies/10/employees/45"

它还包含一个可以用于自定义序列化的ValueTransformerContext变量。例如

  • context.keyCase - 指定键的 casing 风格(.snake.upperCamel.lowerCamel
  • context.explicitNull - 决定是否包含空值的键
  • 指定自定义转换器