From f3c78026270a2d8e288786533a2befa70c868109 Mon Sep 17 00:00:00 2001 From: Jens Ayton Date: Mon, 6 Apr 2020 15:24:49 +0200 Subject: [PATCH] Remove Initiate completely from MobiusLoop Initiation is a MobiusController concern. Note behaviour change: MobiusLoop no longer triggers initiate logs. --- MobiusCore/Source/EventProcessor.swift | 6 ++--- MobiusCore/Source/Mobius.swift | 30 ++--------------------- MobiusCore/Source/MobiusController.swift | 16 +++++++++--- MobiusCore/Source/MobiusLogger.swift | 10 +++++--- MobiusCore/Source/MobiusLoop.swift | 5 ++-- MobiusCore/Test/EventProcessorTests.swift | 10 ++++---- MobiusCore/Test/MobiusLoopTests.swift | 4 --- 7 files changed, 32 insertions(+), 49 deletions(-) diff --git a/MobiusCore/Source/EventProcessor.swift b/MobiusCore/Source/EventProcessor.swift index 435c8f58..ab771ee0 100644 --- a/MobiusCore/Source/EventProcessor.swift +++ b/MobiusCore/Source/EventProcessor.swift @@ -52,11 +52,11 @@ class EventProcessor: Disposable, CustomDebugStringConvert access = accessGuard } - func start(from first: First) { + func start(from model: Model, effects: [Effect]) { access.guard { - currentModel = first.model + currentModel = model - publisher.post(Next.next(first.model, effects: first.effects)) + publisher.post(Next.next(model, effects: effects)) for event in queuedEvents { accept(event) diff --git a/MobiusCore/Source/Mobius.swift b/MobiusCore/Source/Mobius.swift index bf82f187..966e90ba 100644 --- a/MobiusCore/Source/Mobius.swift +++ b/MobiusCore/Source/Mobius.swift @@ -80,7 +80,6 @@ public extension Mobius { return Builder( update: update, effectHandler: effectHandler, - initiate: nil, eventSource: AnyEventSource({ _ in AnonymousDisposable(disposer: {}) }), eventConsumerTransformer: { $0 }, logger: AnyMobiusLogger(NoopLogger()) @@ -111,7 +110,6 @@ public extension Mobius { struct Builder { private let update: Update private let effectHandler: AnyConnectable - private let initiate: Initiate? private let eventSource: AnyEventSource private let logger: AnyMobiusLogger private let eventConsumerTransformer: ConsumerTransformer @@ -119,14 +117,12 @@ public extension Mobius { fileprivate init( update: Update, effectHandler: EffectHandler, - initiate: Initiate?, eventSource: AnyEventSource, eventConsumerTransformer: @escaping ConsumerTransformer, logger: AnyMobiusLogger ) where EffectHandler.Input == Effect, EffectHandler.Output == Event { self.update = update self.effectHandler = AnyConnectable(effectHandler) - self.initiate = initiate self.eventSource = eventSource self.logger = logger self.eventConsumerTransformer = eventConsumerTransformer @@ -150,7 +146,6 @@ public extension Mobius { return Builder( update: update, effectHandler: effectHandler, - initiate: initiate, eventSource: AnyEventSource(eventSource), eventConsumerTransformer: eventConsumerTransformer, logger: logger @@ -169,7 +164,6 @@ public extension Mobius { return Builder( update: update, effectHandler: effectHandler, - initiate: initiate, eventSource: eventSource, eventConsumerTransformer: eventConsumerTransformer, logger: AnyMobiusLogger(logger) @@ -196,7 +190,6 @@ public extension Mobius { return Builder( update: update, effectHandler: effectHandler, - initiate: initiate, eventSource: eventSource, eventConsumerTransformer: { consumer in transformer(oldTransfomer(consumer)) }, logger: logger @@ -209,19 +202,11 @@ public extension Mobius { /// - initialModel: The model the loop should start with. /// - effects: Zero or more effects to execute immediately. public func start(from initialModel: Model, effects: [Effect] = []) -> MobiusLoop { - // If no explicit initiator was given, create one that passes the model through unchanged and applies the - // given effects. - precondition( - self.initiate == nil || effects.isEmpty, - "A loop cannot use withInitiator and also specify initial effects in start" - ) - let initiate = self.initiate ?? { First(model: $0, effects: effects) } - return MobiusLoop.createLoop( update: update, effectHandler: effectHandler, initialModel: initialModel, - initiate: initiate, + effects: effects, eventSource: eventSource, eventConsumerTransformer: eventConsumerTransformer, logger: logger @@ -260,21 +245,10 @@ public extension Mobius { builder: self, initialModel: initialModel, initiate: initiate, + logger: logger, loopQueue: loopQueue, viewQueue: viewQueue ) } - - /// Internal; called by `MobiusController` - func withInitiate(_ initiate: @escaping Initiate) -> Builder { - return Builder( - update: update, - effectHandler: effectHandler, - initiate: initiate, - eventSource: eventSource, - eventConsumerTransformer: eventConsumerTransformer, - logger: logger - ) - } } } diff --git a/MobiusCore/Source/MobiusController.swift b/MobiusCore/Source/MobiusController.swift index 3d3a8036..f05dee93 100644 --- a/MobiusCore/Source/MobiusController.swift +++ b/MobiusCore/Source/MobiusController.swift @@ -58,6 +58,7 @@ public final class MobiusController { builder: Mobius.Builder, initialModel: Model, initiate: Initiate? = nil, + logger: AnyMobiusLogger, loopQueue loopTargetQueue: DispatchQueue, viewQueue: DispatchQueue ) { @@ -125,12 +126,21 @@ public final class MobiusController { } } - var decoratedBuilder = builder.withEventConsumerTransformer(flipEventsToLoopQueue) + // Wrap initiator (if any) in a logger + let actualInitiate: Initiate if let initiate = initiate { - decoratedBuilder = decoratedBuilder.withInitiate(initiate) + actualInitiate = LoggingInitiate(initiate, logger: logger).initiate + } else { + actualInitiate = { First(model: $0) } } - loopFactory = { decoratedBuilder.start(from: $0) } + let decoratedBuilder = builder + .withEventConsumerTransformer(flipEventsToLoopQueue) + + loopFactory = { model in + let first = actualInitiate(model) + return decoratedBuilder.start(from: first.model, effects: first.effects) + } } deinit { diff --git a/MobiusCore/Source/MobiusLogger.swift b/MobiusCore/Source/MobiusLogger.swift index 4dee935e..dfa35cf8 100644 --- a/MobiusCore/Source/MobiusLogger.swift +++ b/MobiusCore/Source/MobiusLogger.swift @@ -25,16 +25,20 @@ public protocol MobiusLogger { associatedtype Event associatedtype Effect - /// Called right before the `Initiate` function is called. + /// Called right before the `Initiate` function is called. /// - /// This method mustn't block, as it'll hinder the loop from running. It will be called on the - /// same thread as the `Initiate` function. + /// This method is only called for `MobiusController`-managed loops. + /// + /// This method mustn't block, as it'll hinder the loop from running. It will be called on the + /// same thread as the `Initiate` function. /// /// - Parameter model: the model that will be passed to the initiate function func willInitiate(model: Model) /// Called right after the `Initiate` function is called. /// + /// This method is only called for `MobiusController`-managed loops. + /// /// This method mustn't block, as it'll hinder the loop from running. It will be called on the /// same thread as the initiate function. /// diff --git a/MobiusCore/Source/MobiusLoop.swift b/MobiusCore/Source/MobiusLoop.swift index 8590f6ce..f50a29c0 100644 --- a/MobiusCore/Source/MobiusLoop.swift +++ b/MobiusCore/Source/MobiusLoop.swift @@ -111,13 +111,12 @@ public final class MobiusLoop: Disposable, CustomDebugStri update: Update, effectHandler: EffectHandler, initialModel: Model, - initiate: @escaping Initiate, + effects: [Effect], eventSource: AnyEventSource, eventConsumerTransformer: ConsumerTransformer, logger: AnyMobiusLogger ) -> MobiusLoop where EffectHandler.Input == Effect, EffectHandler.Output == Event { let accessGuard = ConcurrentAccessDetector() - let loggingInitiate = LoggingInitiate(initiate, logger: logger) let loggingUpdate = update.logging(logger) let workBag = WorkBag(accessGuard: accessGuard) @@ -163,7 +162,7 @@ public final class MobiusLoop: Disposable, CustomDebugStri let nextConnection = nextPublisher.connect(to: nextConsumer) // everything is hooked up, start processing! - eventProcessor.start(from: loggingInitiate.initiate(initialModel)) + eventProcessor.start(from: initialModel, effects: effects) return MobiusLoop( eventProcessor: eventProcessor, diff --git a/MobiusCore/Test/EventProcessorTests.swift b/MobiusCore/Test/EventProcessorTests.swift index 2c2ebd70..7ca6bae0 100644 --- a/MobiusCore/Test/EventProcessorTests.swift +++ b/MobiusCore/Test/EventProcessorTests.swift @@ -47,13 +47,13 @@ class EventProcessorTests: QuickSpec { describe("publishing") { it("should post the first to the publisher as a next") { - eventProcessor.start(from: First(model: 1, effects: [])) + eventProcessor.start(from: 1, effects: []) expect(receivedModels).to(equal([1])) } it("should post nexts to the publisher") { - eventProcessor.start(from: First(model: 1, effects: [])) + eventProcessor.start(from: 1, effects: []) eventProcessor.accept(10) eventProcessor.accept(200) @@ -68,7 +68,7 @@ class EventProcessorTests: QuickSpec { context("given a start from 1") { beforeEach { - eventProcessor.start(from: First(model: 1, effects: [])) + eventProcessor.start(from: 1, effects: []) } it("should track the current model from start") { @@ -87,7 +87,7 @@ class EventProcessorTests: QuickSpec { eventProcessor.accept(80) eventProcessor.accept(400) - eventProcessor.start(from: First(model: 1, effects: [])) + eventProcessor.start(from: 1, effects: []) expect(receivedModels).to(equal([1, 81, 481])) } @@ -108,7 +108,7 @@ class EventProcessorTests: QuickSpec { context("when the event processor has a First") { it("should produce the appropriate debug description") { - eventProcessor.start(from: First(model: 1, effects: [2, 3])) + eventProcessor.start(from: 1, effects: [2, 3]) let description = String(reflecting: eventProcessor) expect(description).to(contain("Optional(<1")) // Due to synced queue its hard to test a processor with events } diff --git a/MobiusCore/Test/MobiusLoopTests.swift b/MobiusCore/Test/MobiusLoopTests.swift index 11b51d13..049bc227 100644 --- a/MobiusCore/Test/MobiusLoopTests.swift +++ b/MobiusCore/Test/MobiusLoopTests.swift @@ -177,10 +177,6 @@ class MobiusLoopTests: QuickSpec { .start(from: "begin") } - it("should log startup") { - expect(logger.logMessages).toEventually(equal(["willInitiate(begin)", "didInitiate(begin, First(model: \"begin\", effects: []))"])) - } - it("should log updates") { logger.clear()