Changeable
允许显式跟踪和观察对象/值所作更改的简单框架。
关于 Changeable
Changable
是一个包装在任何对象上的层,无论是 class
还是 struct
,都可以使用一个公开的 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 和测试中找到,以及在这篇 文章 中。
要求
- Swift 4.0 或更高版本
- macOS 10.9 或更高版本
- iOS 8.0 或更高版本
- watchOS 2.0 或更高版本
- tvOS 9.0 或更高版本
安装
CocoaPods
在您的 Podfile 中添加以下内容
use_frameworks!
target 'TargetName' do
pod 'Changeable'
end
然后运行
pod install
Carthage
在您的 Cartfile 中添加以下内容
github "nonameplum/Changeable"
然后运行
carthage update
许可
Changeable 使用 MIT 许可证发布。