Skip to content

Commit 1668c76

Browse files
committed
Polishing and documentation fixes and improvements.
1 parent 705ee6e commit 1668c76

File tree

6 files changed

+30
-40
lines changed

6 files changed

+30
-40
lines changed

Examples/CaseStudies/UIKitCaseStudies/CounterViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ final class CounterViewController: UIViewController {
6767
rootStackView.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor),
6868
])
6969

70-
self.viewStore.producer
71-
.map { "\($0.count)" }
70+
self.viewStore.publisher.count
71+
.map(String.init)
7272
.assign(to: \.text, on: countLabel)
7373
}
7474

README.md

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
# A Reactive Swift fork of The Composable Architecture
22

3+
[![Swift 5.2](https://img.shields.io/badge/swift-5.2-ED523F.svg?style=flat)](https://swift.org/download/)
4+
[![CI](https://github.com/trading-point/reactiveswift-composable-architecture/workflows/CI/badge.svg)](https://github.com/trading-point/reactiveswift-composable-architecture/actions?query=workflow%3ACI)
5+
36
[Pointfreeco's](https://github.com/pointfreeco) [The Composable Architecture](https://github.com/pointfreeco/swift-composable-architecture) uses Apple's Combine framework as the basis of its `Effect` type. Unfortunately, Combine is only available on iOS 13 and macOS 10.15 and above. In order to be able to use it with earlier versions of the OSes, this fork has adapted The Composable Architecture to use [Reactive Swift](https://github.com/ReactiveCocoa/ReactiveSwift) as the basis for the `Effect` type.
47

5-
Current status:
8+
## Effect type implementations
9+
<details>
10+
<summary>Combine vs ReactiveSwift</summary>
611

7-
* [x] ComposableArchitecture library builds
8-
* [x] ComposableArchitectureTests all pass
9-
* [x] The UIKit Case Studies examples build and run correctly
10-
* [x] The SwiftUI Case Studies examples build and run correctly
11-
* [x] ComposableCoreLocation to builds
12-
* [x] ComposableCoreLocationTests all pass
13-
* [x] All examples projects build and have passing tests.
12+
In Pointfreeco's composable architecture the `Effect` type wraps a Combine `Producer`, and also conforms to the `Publisher` protocol. This is required due to the way that each operation on a `Publisher` (e.g. `map`) returns a new type of Publisher (`Publishers.Map` in the case of `map`), so in order to have a single `Effect` type these publisher types always need to be erased back to just the `Effect` type with `eraseToEffect()`.
1413

15-
The following changes are still needed:
14+
Using ReactiveSwift, which doesn't use Combine's type model, `Effect<Output, Failure>` is simply a typealias for `SignalProducer<Value, Error>`. There is never a need to type erase. Also, due to ReactiveSwift's lifetime based disposable handling, you rarely need to keep a reference to a `Disposable`, unlike in Combine, where you must always keep a reference to any `Cancellable` otherwise it will terminate immediately.
1615

17-
* [ ] Change the documentation (docs and code comments) to reflect the use or ReactiveSwift
16+
</details>
1817

19-
# The Composable Architecture
2018

21-
[![Swift 5.2](https://img.shields.io/badge/swift-5.2-ED523F.svg?style=flat)](https://swift.org/download/)
22-
[![Swift 5.1](https://img.shields.io/badge/swift-5.1-ED523F.svg?style=flat)](https://swift.org/download/)
23-
[![CI](https://github.com/trading-point/swift-composable-architecture/workflows/CI/badge.svg)](https://github.com/trading-point/swift-composable-architecture/actions?query=workflow%3ACI)
24-
[![@pointfreeco](https://img.shields.io/badge/[email protected]?style=flat)](https://twitter.com/pointfreeco)
19+
# The Composable Architecture
2520

2621
The Composable Architecture is a library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind. It can be used in SwiftUI, UIKit, and more, and on any Apple platform (iOS, macOS, tvOS, and watchOS).
2722

@@ -78,8 +73,8 @@ This repo comes with _lots_ of examples to demonstrate how to solve common and c
7873
* Navigation
7974
* Higher-order reducers
8075
* Reusable components
81-
82-
The following examples have not yet been adapted for ReactiveSwift
76+
77+
The following examples have not yet been adapted for ReactiveSwift
8378
* [Location manager](./Examples/LocationManager)
8479
* [Motion manager](./Examples/MotionManager)
8580
* [Search](./Examples/Search)
@@ -232,11 +227,11 @@ It is also straightforward to have a UIKit controller driven off of this store.
232227

233228
// Omitted: Add subviews and set up constraints...
234229

235-
self.viewStore.producer
236-
.map { "\($0.count)" }
230+
self.viewStore.publisher
231+
.map(String.init)
237232
.assign(to: \.text, on: countLabel)
238233

239-
self.viewStore.producer.numberFactAlert
234+
self.viewStore.publisher.numberFactAlert
240235
.startWithValues { [weak self] numberFactAlert in
241236
let alertController = UIAlertController(
242237
title: numberFactAlert, message: nil, preferredStyle: .alert
@@ -421,7 +416,7 @@ If you are interested in contributing a wrapper library for a framework that we
421416

422417
You would probably still want something like a `UIScheduler` so that you don't needlessly perform thread hops.
423418
</details>
424-
419+
425420
## Requirements
426421

427422
This fork of The Composable Architecture uses the ReactiveSwift framework, it currently requires minimum deployment targets of iOS 12, macOS 10.14, Mac Catalyst 14, tvOS 14, and watchOS 5, although it may be possible to support earlier versions too.
@@ -431,7 +426,7 @@ This fork of The Composable Architecture uses the ReactiveSwift framework, it cu
431426
You can add ComposableArchitecture to an Xcode project by adding it as a package dependency.
432427

433428
1. From the **File** menu, select **Swift Packages › Add Package Dependency…**
434-
2. Enter "https://github.com/trading-point/swift-composable-architecture" into the package repository URL text field
429+
2. Enter "https://github.com/trading-point/reactiveswift-composable-architecture" into the package repository URL text field
435430
3. Depending on how your project is structured:
436431
- If you have a single application target that needs access to the library, then add **ComposableArchitecture** directly to your application.
437432
- If you want to use this library from multiple targets you must create a shared framework that depends on **ComposableArchitecture** and then depend on that framework in all of your targets. For an example of this, check out the [Tic-Tac-Toe](./Examples/TicTacToe) demo application, which splits lots of features into modules and consumes the static library in this fashion using the **TicTacToeCommon** framework.
@@ -463,7 +458,7 @@ There are also many architecture libraries in the Swift and iOS community. Each
463458
* [Mobius.swift](https://github.com/spotify/mobius.swift)
464459
* <details>
465460
<summary>And more</summary>
466-
461+
467462
* [PromisedArchitectureKit](https://github.com/RPallas92/PromisedArchitectureKit)
468463
</details>
469464

Sources/ComposableArchitecture/Effect.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import ReactiveSwift
1111
/// must receive values on the main thread.
1212
///
1313
/// An effect is simply a typealias for a ReactiveSwift `SignalProducer`
14-
/// constructing some common types of effects.
1514
public typealias Effect<Value, Error: Swift.Error> = SignalProducer<Value, Error>
1615

1716
extension Effect {

Sources/ComposableArchitecture/Store.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public final class Store<State, Action> {
197197
}
198198
}
199199

200-
// A publisher of store state.
200+
/// A publisher of store state.
201201
@dynamicMemberLookup
202202
public struct StorePublisher<State>: SignalProducerConvertible {
203203
public let producer: Effect<State, Never>

Sources/ComposableArchitecture/SwiftUI/ViewStore.swift

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ import SwiftUI
3434
/// super.viewDidLoad()
3535
///
3636
/// self.viewStore.publisher.count
37-
/// .sink { [weak self] in self?.countLabel.text = $0 }
38-
/// .store(in: &self.cancellables)
37+
/// .startWithValues { [weak self] in self?.countLabel.text = $0 }
3938
/// }
4039
///
4140
/// @objc func incrementButtonTapped() {
@@ -48,8 +47,6 @@ public final class ViewStore<State, Action>: ObservableObject {
4847
public let publisher: StorePublisher<State>
4948
public let producer: SignalProducer<State, Never>
5049

51-
private var viewCancellable: Disposable?
52-
5350
/// Initializes a view store from a store.
5451
///
5552
/// - Parameters:
@@ -64,12 +61,11 @@ public final class ViewStore<State, Action>: ObservableObject {
6461
self.publisher = StorePublisher(producer)
6562
self.state = store.state
6663
self._send = store.send
67-
self.viewCancellable = producer.startWithValues { [weak self] in self?.state = $0 }
68-
69-
if #available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) {
70-
self.producer.startWithValues { _ in
71-
self.objectWillChange.send()
64+
producer.startWithValues { [weak self] in
65+
if #available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) {
66+
self?.objectWillChange.send()
7267
}
68+
self?.state = $0
7369
}
7470
}
7571

Sources/ComposableArchitecture/TestSupport/TestStore.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
/// case let .queryChanged(query):
6767
/// state.query = query
6868
/// return environment.request(self.query)
69-
/// .debounce(id: SearchId(), for: 0.5, scheduler: environment.mainQueue)
69+
/// .debounce(id: SearchId(), interval: 0.5, scheduler: environment.mainQueue)
7070
/// case let .response(results):
7171
/// state.results = results
7272
/// return .none
@@ -95,15 +95,15 @@
9595
/// $0.query = "c"
9696
/// },
9797
/// // Advance the scheduler by a period shorter than the debounce
98-
/// .do { scheduler.advance(by: 0.25) },
98+
/// .do { scheduler.advance(by: .millseconds(250)) },
9999
/// // Change the query again
100100
/// .send(.searchFieldChanged("co") {
101101
/// $0.query = "co"
102102
/// },
103103
/// // Advance the scheduler by a period shorter than the debounce
104-
/// .do { scheduler.advance(by: 0.25) },
104+
/// .do { scheduler.advance(by: .millseconds(250)) },
105105
/// // Advance the scheduler to the debounce
106-
/// .do { scheduler.advance(by: 0.25) },
106+
/// .do { scheduler.advance(by: .millseconds(250)) },
107107
/// // Assert that the expected response is received
108108
/// .receive(.response(["Composable Architecture"])) {
109109
/// // Assert that state updates accordingly

0 commit comments

Comments
 (0)