Skip to content

Commit

Permalink
SideEffects for autoremovable observer (#29)
Browse files Browse the repository at this point in the history
* added side effects with auto removable observer

* minor fixes
  • Loading branch information
KazaiMazai authored Aug 22, 2024
1 parent c215f86 commit 9b123c2
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 5 deletions.
116 changes: 113 additions & 3 deletions Sources/Puredux/SideEffects/SideEffects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Dispatch
import Foundation

// MARK: - Store Effects
extension Store {
func effect(on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) where State == Effect.State {
Expand Down Expand Up @@ -36,6 +37,8 @@ extension Store {
}
}

// MARK: - StateStore Effects

extension StateStore {
func effect(on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) where State == Effect.State {
Expand Down Expand Up @@ -63,20 +66,22 @@ extension StateStore {
strongStore().effect(on: queue, create: create)
}

func effect(withDebounce timeInterval: TimeInterval,
func effect(withDelay timeInterval: TimeInterval,
removeStateDuplicates: Equating<State>?,
on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) {

strongStore().effect(
withDebounce: timeInterval,
withDelay: timeInterval,
removeStateDuplicates: removeStateDuplicates,
on: queue,
create: create
)
}
}

// MARK: - StateStore Effects

extension StateStore {
func forEachEffect<Effects>(_ keyPath: KeyPath<State, Effects>,
on queue: DispatchQueue = .main,
Expand Down Expand Up @@ -186,14 +191,119 @@ extension Store {
)
}

func effect(withDebounce timeInterval: TimeInterval,
func effect(withDelay timeInterval: TimeInterval,
removeStateDuplicates: Equating<State>?,
on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) {

let effectOperator = EffectOperator()

subscribe(observer: Observer(
removeStateDuplicates: removeStateDuplicates) { [effectOperator] state, prevState, complete in
effectOperator.run(.running(delay: timeInterval), on: queue) { _ in
create(state)
}
complete(.active)
return effectOperator.isSynced ? state : prevState
}
)
}
}

extension Store {
func forEachEffect<Effects>(_ observer: AnyObject,
_ keyPath: KeyPath<State, Effects>,
on queue: DispatchQueue = .main,
create: @escaping (State, Effect.State) -> Effect)
where Effects: Collection & Hashable, Effects.Element == Effect.State {

let effectOperator = EffectOperator()

subscribe(observer: Observer(
observer,
removeStateDuplicates: .keyPath(keyPath)) { [effectOperator] state, prevState, complete in

let allEffects = state[keyPath: keyPath]
effectOperator.run(allEffects, on: queue) { effectState in
create(state, effectState)
}
complete(.active)
return effectOperator.isSynced ? state : prevState
}
)
}

func effect(_ observer: AnyObject,
_ keyPath: KeyPath<State, Effect.State>,
on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) {

let effectOperator = EffectOperator()

subscribe(observer: Observer(
observer,
removeStateDuplicates: .keyPath(keyPath)) { [effectOperator] state, prevState, complete in

let effect = state[keyPath: keyPath]
effectOperator.run(effect, on: queue) { _ in
create(state)
}
complete(.active)
return effectOperator.isSynced ? state : prevState
}
)
}

func effect<T>(_ observer: AnyObject,
_ keyPath: KeyPath<State, T>,
on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) where T: Equatable {

let effectOperator = EffectOperator()

subscribe(observer: Observer(
observer,
removeStateDuplicates: .keyPath(keyPath)) { [effectOperator] state, prevState, complete in
let effect: Effect.State = prevState == nil ? .idle() : .running()
effectOperator.run(effect, on: queue) { _ in
create(state)
}
complete(.active)
return effectOperator.isSynced ? state : prevState
}
)
}

func effect(_ observer: AnyObject,
_ keyPath: KeyPath<State, Bool>,
on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) {

let effectOperator = EffectOperator()

subscribe(observer: Observer(
observer,
removeStateDuplicates: .keyPath(keyPath)) { [effectOperator] state, prevState, complete in

let isRunning = state[keyPath: keyPath]
effectOperator.run(isRunning, on: queue) { _ in
create(state)
}
complete(.active)
return effectOperator.isSynced ? state : prevState
}
)
}
func effect(_ observer: AnyObject,
withDelay timeInterval: TimeInterval,
removeStateDuplicates: Equating<State>?,
on queue: DispatchQueue = .main,
create: @escaping (State) -> Effect) {

let effectOperator = EffectOperator()

subscribe(observer: Observer(
observer,
removeStateDuplicates: removeStateDuplicates) { [effectOperator] state, prevState, complete in
effectOperator.run(.running(delay: timeInterval), on: queue) { _ in
create(state)
Expand Down
26 changes: 26 additions & 0 deletions Sources/Puredux/Store/Observer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,32 @@ extension Observer {
}
}

init(_ observer: AnyObject,
id: UUID = UUID(),
removeStateDuplicates equating: Equating<State>? = nil,
observe: @escaping StatesObserver) {

self.id = id
self.keepsCurrentState = equating != nil
self.stateHandler = { [weak observer] state, prevState, complete in
guard observer != nil else {
complete(.dead)
return state
}

guard let equating else {
return observe(state, prevState, complete)
}

guard !equating.isEqual(state, to: prevState) else {
complete(.active)
return state
}

return observe(state, prevState, complete)
}
}

init(id: UUID = UUID(),
keepsCurrentState: Bool,
observe: @escaping StatesObserver) {
Expand Down
4 changes: 2 additions & 2 deletions Sources/Puredux/UIKit/Presentable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public extension Presentable {

let weakRefStore = store.weakStore()
presenter = Presenter { [weak self] in
store.effect(withDebounce: .uiDebounce,
store.effect(withDelay: .uiDebounce,
removeStateDuplicates: equating,
on: presentationQueue.dispatchQueue) { state in

Expand All @@ -48,7 +48,7 @@ public extension Presentable {
removeStateDuplicates equating: Equating<State>? = nil) {

presenter = Presenter { [weak self] in
store.effect(withDebounce: .uiDebounce,
store.effect(withDelay: .uiDebounce,
removeStateDuplicates: equating,
on: presentationQueue.dispatchQueue) { state in

Expand Down

0 comments on commit 9b123c2

Please sign in to comment.