Swiftpack.co - Package - tcldr/Entwine


CI @tcldr1

Accessories for Apple's Combine Framework.


Entwine consists of three libraries (over two repositories) to be used in conjuction with Apple's Combine framework:

Note: EntwineRx is maintained as a separate Swift package to minimize the SPM dependency graph.

Quick start guide

Create Combine publishers from any source

Use the Publishers.Factory publisher from the Entwine package to effortlessly create a publisher that meets Combine's backpressure requirements from any source. Find out more about the Entwine Utilities library.

Inline publisher creation for PhotoKit authorization status:

import Entwine

let photoKitAuthorizationStatus = Publishers.Factory<PHAuthorizationStatus, Never> { dispatcher in
    let status = PHPhotoLibrary.authorizationStatus()
    switch status {
    case .notDetermined:
        PHPhotoLibrary.requestAuthorization { newStatus in
            dispatcher.forward(completion: .finished)
        dispatcher.forward(completion: .finished)
    return AnyCancellable {}

Unit test Combine publisher sequences

Use the TestScheduler, TestablePublisher and TestableSubscriber to simulate Combine sequences and test against expected output. Find out more about the EntwineTest library

Testing Combine's map(_:) operator:

import XCTest
import EntwineTest
func testMap() {
    let testScheduler = TestScheduler(initialClock: 0)
    // creates a publisher that will schedule it's elements relatively, at the point of subscription
    let testablePublisher: TestablePublisher<String, Never> = testScheduler.createRelativeTestablePublisher([
        (100, .input("a")),
        (200, .input("b")),
        (300, .input("c")),
    let subjectUnderTest = testablePublisher.map { $0.uppercased() }
    // schedules a subscription at 200, to be cancelled at 900
    let results = testScheduler.start { subjectUnderTest }
    XCTAssertEqual(results.recordedOutput, [
        (200, .subscription),           // subscribed at 200
        (300, .input("A")),             // received uppercased input @ 100 + subscription time
        (400, .input("B")),             // received uppercased input @ 200 + subscription time
        (500, .input("C")),             // received uppercased input @ 300 + subscription time

Bridge your RxSwift view models to Combine and use with SwiftUI

First, make sure you add the EntwineRx Swift Package (located in an external repo) as a dependency to your project.

Example coming soon


Entwine sits on top of Apple's Combine framework and therefore requires Xcode 11 and is has minimum deployment targets of macOS 10.15, iOS 13, tvOS 13 or watchOS 6.


Entwine is delivered via a Swift Package and can be installed either as a dependency to another Swift Package by adding it to the dependencies section of a Package.swift file or to an Xcode 11 project by via the File -> Swift Packages -> Add package dependency... menu in Xcode 11.


Documentation for each package is available at:

Copyright and license

This project is released under the MIT license


Stars: 202



Congruence.1 - 2020-07-15 08:17:02

Fixes issue with EntwineTest's scheduler that prevented repeating intervals from being called. This affected the behavior of publishers that rely on this capability such as CollectByTime and Debounce. Thanks for the heads-up @iwheelbuy!

Congruence - 2020-05-13 16:21:48

WARNING: Source breaking. Various tweaks to make Entwine perform in congruence with Combine – including the removal of the obsolete CancellableBag which has since been superseded by AnyCancellable's store(in:) family of functions.

Re-ReplaySubject - 2019-10-31 09:55:02

  • Adds referenceCounted() operator for Multicast publishers
  • Moves share(replay:) to use referenceCounted() instead of autoconnect() – matching wider reactive community implementations.

Thanks to @sherlock1982 for raising the issue!

DeallocToken - 2019-07-30 14:18:14

Adds DeallocToken utility plus temporary fix for Xcode 11 beta 5 Subject API additions.

Signpost - 2019-07-19 10:11:24

Includes a new signpost operator that enables easy performance logging for your Combine sequences. Use the operator to generate ranged os_signpost logs of publisher events that can be visualised in Instruments.

Also, for additional clarity, TestableSubscriber's sequence and demands properties have been renamed to recordedOutput and recordedDemandLog respectively. Thanks to @heckj for the suggestion!

Fourtitude - 2019-07-17 19:12:13

Updated to reflect API changes in latest Combine beta that arrived with Xcode 11 beta 4.

Final Demand? - 2019-07-03 10:24:21

Updated to reflect API changes in latest Combine beta that arrived with Xcode 11 beta 3. In particular, Subscribers.Demand has been changed from an enum to a struct and is far stricter in regards to allowing negative demand balances.

Cancelled, but not completed. - 2019-06-26 10:33:11

This release changes the cancellation behaviour to match that described at https://twitter.com/millenomi/status/1137382877870510080.

Namely, a publisher does not need to generate a completion event upon cancellation.

Bag O' Cancel - 2019-06-25 11:31:27

Adds CancellationBag and some documentation updates and fixes

MVP - 2019-06-24 16:42:31

Initial release.