可更改 0.5

Changeable 0.5

测试已测试
Lang语言 SwiftSwift
许可 MIT
发布最新发布2019年4月
SPM支持 SPM

Lukasz Sliwinski维护。



  • 作者
  • Łukasz Śliwiński

Changeable

允许显式跟踪和观察对象/值所作更改的简单框架。

Changeable

Swift4 CocoaPods Carthage Platform Lincense


关于 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 许可证发布。