Changable
是一个对象上的包装器,无论它是 class
还是 struct
,都可以使用暴露的方法 set
来更改。与普通 set 不同的是,使用 set
方法所做的所有更改不会立即应用,而是在使用 commit
方法之后应用。为了完全满足需求,Changeable
还允许您使用 reset
方法重置待处理的更改。
此外,Changeable
允许您检查当前的待处理更改和上次进行的更改。 同时,可以通过在生命周期内发生的更改来观察 Changeable
。
这提供了对您感兴趣的特定状态变化做出反应的机会。
示例
struct SomeState {
var isLoading: Bool
var counter: Int
}
let state = Changeable<SomeState>(value: SomeState(isLoading: false, counter: 0))
state.set(for: \SomeState.counter, value: 1)
print(state.pendingChanges.count) // 1
print(state.pendingChanges.contains(\SomeState.counter)) // true
state.commit()
print(state.value.counter) // 1
state.set(for: \SomeState.isLoading, value: true)
state.reset()
print(state.value.isLoading) // false
// Observer will be notifed once for every commit
// We can observe only changes that match keyPaths
let disposable = state.add(matching: [\SomeState.isLoading], observer: { change in
if let isLoading = change.changeMatching(\SomeState.isLoading) {
print("⏳ Loading: \(isLoading)")
}
if change ~= [\SomeState.isLoading] {
print("Contains change isLoading")
}
if change.changedKeyPaths == [\SomeState.isLoading, \SomeState.counter] {
// Sorry, no
}
})
state.set(for: \SomeState.isLoading, value: true)
state.commit() // Observer called
disposable.dispose()
// We could define change cases that we are interested in
extension Change where T == SomeState {
enum StateChange {
case everything
case loading
var changesDefinition: Set<PartialKeyPath<T>> {
switch self {
case .everything:
return Set([\SomeState.counter, \SomeState.isLoading])
case .loading:
return Set([\SomeState.isLoading])
}
}
}
func changesEqual(to change: StateChange) -> Bool {
return change.changesDefinition == changedKeyPaths
}
}
// We can also use diposeBag in the same way like RxSwift to handle more than one disposable in one place
var disposeBag: DisposeBag! = DisposeBag()
state.add(observer: { change in
if change ~= Change<SomeState>.StateChange.loading.changesDefinition {
print("Contains change isLoading")
}
// Or
if change.changesEqual(to: .everything) {
print("Everything has changed")
}
}).addDisposableTo(disposeBag)
state.set(for: \SomeState.counter, value: 2)
state.set(for: \SomeState.isLoading, value: false)
state.commit()
disposeBag = nil
// We can always check last changes
if let lastCounterValue = state.lastChangeMatching(\SomeState.counter) {
print("Last changed counter value: \(lastCounterValue)")
}
if state.lastChanges.contains(\SomeState.isLoading) {
print("The last changes contain loading change")
}
您将在 playground、测试以及这篇文章中找到更多示例。
将以下内容添加到您的 Podfile 中
use_frameworks!
target 'TargetName' do
pod 'Changeable'
end
并运行
pod install
将以下内容添加到您的 Cartfile 中
github "nonameplum/Changeable"
并运行
carthage update
Changeable 在 MIT 许可下发布。