可变的

一个简单的框架,允许您显式地跟踪和观察对象/值中所做的更改。

Changeable

Swift4 CocoaPods Carthage Platform Lincense


关于 Changeable

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、测试以及这篇文章中找到更多示例。


要求


安装

CocoaPods

将以下内容添加到您的 Podfile 中

use_frameworks!

target 'TargetName' do
  pod 'Changeable'
end

并运行

pod install

Carthage

将以下内容添加到您的 Cartfile 中

github "nonameplum/Changeable"

并运行

carthage update

许可

Changeable 在 MIT 许可下发布。