介绍
将任何对象转换为离散系统,并声明式地描述其状态。
如何安装
推荐使用 CocoaPods 安装。
pod 'XCEFunctionalState', '~> 2.8'
它是如何工作的
此库允许通过定义一组不同的状态,并将这些状态应用于对象来将其转换为 离散系统。
如何使用
此库的典型用例是使用它来重新配置 UIView
及其子类实例,以便在您的应用程序状态更改时重新配置。
状态
每个状态都定义了其应用的规则以及如何更新(在它被请求应用而已处于当前状态时),以及一系列操作转换(默认为立即转换)。
有状态的
例如,我们有一个名为SearchView
的类,它代表一个文本字段视图和一个启动搜索过程的按钮。它必须遵循有状态的
协议才能成为一个独立的系统。
import XCEFunctionalState
class SearchView: Stateful
{
let keyword = UITextField()
let start = UIButton()
private(set)
lazy
var state: Dispatcher<MyView> = Dispatcher(for: self)
}
为了描述类的状态,在这个类内部定义一个类级别函数(它的名称将被解释为状态名称),该函数返回一个对该类的状态
。
例如,让我们为我们的SearchView
类定义一个awaiting
状态,其中keyword
文本字段和start
按钮都可以使用并且可以供用户输入。请注意,我们可以定义任意多的输入参数作为该函数的参数,这为我们提供了从外部将任何类型的值传递到状态配置闭包的机会。下面是如何传递keyword
字段的默认值。
extension SearchView
{
static
func awaiting(with keyword: String) -> State<SearchView>
{
return state{
$0.keyword.text = keyword
$0.keyword.isEnabled = true
$0.start.isEnabled = true
}
}
}
当用户输入了搜索关键字并按下start
按钮后,我们可能想要在搜索进行时锁定这些控件。要做到这一点,我们可能需要将locked
状态应用于搜索视图,这可以声明如下
extension SearchView
{
static
func locked() -> State<SearchView>
{
return state{
$0.keyword.isEnabled = false
$0.start.isEnabled = false
}
}
}
稍后,我们可以将类中声明的任何状态应用于这个类的实例,如下所示
let transition: Transition<SearchView> = ... // define transition
let view = SearchView()
view.state.apply{ $0.awaiting(with: "something") }
view.state.apply{ $0.awaiting(with: "another value") } // no effect
view.state.apply(via: transition, MyView.locked()){ /* completion*/ }
//...
view.state.apply{ $0.awaiting(with: "after search") }
默认情况下,所有变异都是立即应用的。当使用基于UIView
的类工作时,使用动画来应用更改是常见的,并且转换
类型提供了完全的控制。
有状态的
协议还允许定义在应用状态时应默认使用的转换,但在状态定义中不提供特定的转换。
extension SearchView
{
static
var defaultOnSetTransition: Transition<SearchView> = {
(view, mutations, completion) in
view.alpha = 0.0
//---
mutations() // this is closure from the state
//---
UIView.animate(
withDuration: 1.0,
animations: { v.alpha = 1.0 },
completion: completion
)
}
static
var defaultOnUpdateTransition: Transition<SearchView> = {
//...
}
}
上例中的`defaultOnSetTransition`展示了隐藏整个视图的转换,然后应用新状态中的变异,最后使用动画使整个视图再次可见。或者,如果需要,我们可以在`UIImageView.animate(…)`调用中调用`mutations()`来在淡入动画中动画实际变异。
与Objective-C的互操作性
为了使代码尽可能简洁、易于理解,并保持编译时的类型安全,这个库依赖于Swift语言的先进功能,如泛型和 closures 简写参数名称,因此它**不**旨在与Objective-C兼容。