content for Using Combine - notes on learning Combine with UIKit and SwiftUI

Overview

Using Combine

SwiftUI-Notes Build Status

A collection of notes, project pieces, playgrounds and ideas on learning and using SwiftUI and Combine. Changes, corrections, and feedback all welcome! See CONTRIBUTING for details and links.

Goal

While I started digging into SwiftUI, I was attracted to Combine and realized how much depth there was in just the Combine framework. I wanted to learn Combine, and describing how to use it to other people works really well for me.

My goal for this is to create easily accessible reference documentation for myself, and for anyone else wanting to use it. I do (not-so-secretly) hope that Apple's own reference documentation will completely obviate the reference section of all of this, but it doesn't today.

What makes good reference documentation for me:

  • core concepts in some detail, explaining what's intended and expected
  • reference of all of the classes and functions you might use, organized and grouped by why you might be using them
    • having commented sample code that illustrate how the function or class can be used
  • common or frequent recipes/patterns of how you might want to use this framework
  • how to test/validate your own creations using the framework

Bonus points:

  • internal self-references to functions, classes, and concepts to supporting navigating based on what you're trying to learn or understand
    • self-consistent navigation of rendered content
  • usable from mobile & desktop
  • diagrams for the functions to make what they do more easily understood (aka marble diagrams)
  • consumable in multiple formats: hosted HTML, pdf, epub
    • hosted HTML easily referencable from source code

Where stuff resides

The docs directory in this repository is the source for the HTML content hosted at https://heckj.github.io/swiftui-notes/

The project (SwiftUI-Notes.xcodeproj) has sample code, tests, and trials used in building and vetting the content.

The content is hosted by Github (on github pages), generated with Jekyll, primarily written in Markdown.

Setting up asciidoctor for local rendering

  • get a more recent ruby (I'm using rbenv with brew install rbenv), current 2.6.3

The git metadata requires "rugged", which wants cmake to install it... so you might need to brew install cmake to make this all work.

rbenv install 2.6.3
rbenv global 2.6.3

gem install bundler
gem install asciidoctor
NOKOGIRI_USE_SYSTEM_LIBRARIES=1 gem install asciidoctor-epub3 --pre
gem install pygments.rb

gem install rugged # required for the git-metadata extension, requires 'cmake'

If you have docker installed, you can also use a docker image to do the rendering, and not have to install anything directly. If you want to try out different extensions, you probably want to install this locally, but if you're just generating the output then the docker path is significantly easier.

The "official" image is asciidoctor/docker-asciidoctor. I have a small variant at heckj/docker-asciidoctor that is built to include the gem rugged which is providing the git metadata resolution.

Rendering - using locally installed asciidoctor & tooling

cd docs

asciidoctor-epub3 -v -t -D output \
  using-combine-book.adoc

asciidoctor-pdf -v -t -D output \
  using-combine-book.adoc

asciidoctor -v -t -D output \
  -r ./lib/google-analytics-docinfoprocessor.rb \
  using-combine-book.adoc

Rendering - using a docker-based toolchain

You can do all this rendering locally with docker. Do this from the top of the repository:

# get the docker image loaded locally
docker pull heckj/docker-asciidoctor

# render the HTML, results will appear in `output` directory
docker run --rm -v $(pwd):/documents/ --name asciidoc-to-html heckj/docker-asciidoctor asciidoctor -v -t -D /documents/output -r ./docs/lib/google-analytics-docinfoprocessor.rb docs/using-combine-book.adoc

# render a PDF, results will appear in `output` directory
docker run --rm -v $(pwd):/documents/ --name asciidoc-to-pdf heckj/docker-asciidoctor asciidoctor-pdf -v -t -D /documents/output docs/using-combine-book.adoc

# render an epub3 file, will should appear in `output` directory
docker run --rm -v $(pwd):/documents/ --name asciidoc-to-epub3 heckj/docker-asciidoctor asciidoctor-epub3 -v -t -D /documents/output docs/using-combine-book.adoc

# copy in the images for the HTML
cp -r docs/images output/images

A variation of these commands are included in the .travisCI build configuration.

Link Validation

There's an NPM package that will hit a page and do a scan for broken links: https://www.npmjs.com/package/broken-link-checker[broken-link-checker].

To install:

npm install broken-link-checker

To run it against the live site:

./node_modules/.bin/blc http://heckj.github.io/swiftui-notes/ | grep BROKEN

Command-line build and test

xcodebuild test -scheme SwiftUI-Notes -allowProvisioningUpdates
Comments
  • How to use combine for text entered into a SwiftUI Textfield?

    How to use combine for text entered into a SwiftUI Textfield?

    Hi,

    first: Great document. The most complete and understandable text explaining the combine framework! Keep up the good work!

    In one of the WWDC session (https://developer.apple.com/videos/play/wwdc2019/712/ starting at 11m 50s) the presenter explains how to process the stream of text coming from a TextField. Unfortunately the presentation does this all on slides, there is never any concrete code or a demo.

    For your "Patterns" section: How would you do this using a TextField from SwiftUI?

    I found some examples using PassthroughSubject, but ideally there should be an easier way to subscribe to text changes from a TextField.

    enhancement 
    opened by dirk68-fu 10
  • `Retry after delay` operator

    `Retry after delay` operator

    Is there a clean way to write Retry after delay operator that would wait for some time and retry on error.

    An alternative I can imagine is to wrap throwing an error in some sort of DispatchQueue.asyncAfter and combine it with retry operator after.

    enhancement question 
    opened by anechaev 7
  • Completion-aware publishers

    Completion-aware publishers

    Hi Joseph,

    I was wondering if there are "Completion-aware" operators in Combine, such as the ReactiveSwift or RxSwift then operator, which lets you start a new publisher once the upstream have finished successfully (in case of failure, the error will be forwarded downstream). Any ideas?

    Combine do have allSatisfy which can be tweaked for that purpose, but I guess it will be better to have a specific Publisher and I don't know how to create custom Publishers yet :)

    Keep up the great work!

    question 
    opened by dehesa 6
  • add some sort of link checker to the generated output

    add some sort of link checker to the generated output

    It'd be sufficient to run a validation against the generated HTML (since the PDF and ePub use the same links), but some of the links I started with in beta2 have definitely gone out of date, and I'm not entirely sure I've caught them all.

    I could really use something to read through the whole HTML page, gather up all the links and then validate that they work - but especially for the external links, as internal references I at least get warnings from AsciiDoctor.

    enhancement 
    opened by heckj 5
  • UIKit-Combine Black Screen while running

    UIKit-Combine Black Screen while running

    UIKit-Combine while Launching in iOS simulator shows Black Screen. Solution: Create an new project copy paste ViewController.swift & Main.storyboard. Compile & run in iOS simulator it works. Image attached for reference only. Black-Screen

    opened by nanujogi 5
  • Doesn't build with Xcode 14.1 (with built-in MacOSX13.0.sdk) on macOS 12 Monterey

    Doesn't build with Xcode 14.1 (with built-in MacOSX13.0.sdk) on macOS 12 Monterey

    "sudo gem install rugged" fails: -- Build files have been written to: /Library/Ruby/Gems/2.6.0/gems/rugged-1.5.0.1/vendor/libgit2/build -- /usr/bin/make checking for -lgit2... *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options.

    --without-git2lib
    

    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/mkmf.rb:467:in `try_do': The compiler failed to generate an executable file. (RuntimeError) You have to install development tools first.

    To see why this extension failed to compile, please check the mkmf.log which can be found here: /Library/Ruby/Gems/2.6.0/extensions/universal-darwin-21/2.6.0/rugged-1.5.0.1/mkmf.log extconf failed, exit code 1

    Gem files will remain installed in /Library/Ruby/Gems/2.6.0/gems/rugged-1.5.0.1 for inspection. Results logged to /Library/Ruby/Gems/2.6.0/extensions/universal-darwin-21/2.6.0/rugged-1.5.0.1/gem_make.out

    [100%] Linking C static library ../../libgit2.a /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(openssl_dynamic.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(openssl_legacy.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(auth_negotiate.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(winhttp.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(pcre_string_utils.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(openssl_dynamic.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(openssl_legacy.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(auth_negotiate.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(winhttp.c.o) has no symbols /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib: file: ../../libgit2.a(pcre_string_utils.c.o) has no symbols [100%] Built target libgit2package "xcrun clang -o conftest -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/universal-darwin21 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/backward -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0 -I. -I/Library/Ruby/Gems/2.6.0/gems/rugged-1.5.0.1/ext/rugged/../../vendor/libgit2/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -g -Os -pipe -DHAVE_GCC_ATOMIC_BUILTINS -DUSE_FFI_CLOSURE_ALLOC -g -O3 -Wall -Wno-comment conftest.c -L/Library/Ruby/Gems/2.6.0/gems/rugged-1.5.0.1/ext/rugged/../../vendor/libgit2/build -L. -L/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib -L. -L/AppleInternal/Library/BuildRoots/c188b140-2ff3-11ed-a7e5-ca9c01dc79de/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.6.Internal.sdk/usr/local/lib -L/usr/local/lib -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/usr/lib -lgit2 -framework CoreFoundation -framework Security -lz -liconv -lruby.2.6 " In file included from conftest.c:1: In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby.h:33: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/ruby.h:24:10: fatal error: 'ruby/config.h' file not found #include "ruby/config.h" ^~~~~~~~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/ruby.h:24:10: note: did not find header 'config.h' in framework 'ruby' (loaded from '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks')

    % which ruby /usr/bin/ruby % ruby -v ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.x86_64-darwin21]

    opened by Fesh-com 4
  • How to export and generate docset format?

    How to export and generate docset format?

    Describe the solution you'd like A clear and concise description of what you want to see added or updated.

    Because of the instability of the network, I want to generate a docset file to use in dash App, so I can quickly preview relevant content locally.

    enhancement 
    opened by iT-Boyer 4
  • Please turn off right justification

    Please turn off right justification

    Can I suggest turning off right justification when publishing a book?

    This makes books especially hard to read especially on small screens. The html version does this correctly but epub and pdf do not.

    enhancement 
    opened by philosopherdog 4
  • Typo on Core Concepts Page

    Typo on Core Concepts Page

    Typo here: “Combine also goes farther than defining the resut, it”

    Excerpt From Using Combine Joseph Heck This material may be protected by copyright.

    bug 
    opened by bendinwire 3
  • "Operator is an object that acts both like a subscriber and a publisher" - Is this true?

    The following text in Core Concepts -> Publisher and Subscriber section confuses me:

    The third core concept is an operator - an object that acts both like a subscriber and a publisher. Operators are classes that adopt both the Subscriber protocol and Publisher protocol. They support subscribing to a publisher, and sending results to any subscribers.

    Is it a copy-paste typo? I think operators are methods that operate on an Observable and return an Observable. See RX ofiical doc here.

    I think the above text seems to describe subject (though subject in combine doesn't implement publisher protocol).

    question 
    opened by rayx 3
  • No Version string in epub document

    No Version string in epub document

    I had 0.8 EPUB installed on an iPad. Downloaded 0.9, tried to launch it - but I think I got 0.8. Then I found there was no version string anywhere. I quit, retried again, got the latest release.

    It would just be nice to be able to tell quickly what version of the document is open. Thanks!

    enhancement 
    opened by dhoerl 3
  • Throttle and debounce timing diagram maybe wrong

    Throttle and debounce timing diagram maybe wrong

    My device is M1 Macbook Air. I tested it in Swift Playground, but the result does not match the timing diagram. I think the time of the result in the third row is drawn in the wrong place. All codes and results are as follows:

    import Foundation
    import Combine
    
    let bounces:[(Int,TimeInterval)] = [
        (1, 10),
        (2, 20),
        (3, 80),
        (4, 90),
        (5, 150),
        (6, 160)
    ]
    
    var startTime = Date().timeIntervalSince1970
    let subject = PassthroughSubject<Int, Never>()
    var cancellable = subject
        .throttle(for: .seconds(50), scheduler: RunLoop.main, latest: true)
        .sink { index in
            let offset = Date().timeIntervalSince1970 - startTime
            print ("Received index \(index) at \(offset)")
        }
    
    for bounce in bounces {
        DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) {
            subject.send(bounce.0)
        }
    }
    

    Received index 1 at 10. 297373294830322 Received index 2 at 60. 29852819442749 Received index 4 at 110. 29963707923889 Received index 6 at 164. 99856996536255

    import Foundation
    import Combine
    
    let bounces:[(Int,TimeInterval)] = [
        (1, 10),
        (2, 20),
        (3, 80),
        (4, 90),
        (5, 150),
        (6, 160)
    ]
    
    var startTime = Date().timeIntervalSince1970
    let subject = PassthroughSubject<Int, Never>()
    var cancellable = subject
        .throttle(for: .seconds(50), scheduler: RunLoop.main, latest: false)
        .sink { index in
            let offset = Date().timeIntervalSince1970 - startTime
            print ("Received index \(index) at \(offset)")
        }
    
    for bounce in bounces {
        DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) {
            subject.send(bounce.0)
        }
    }
    

    Received index 1 at 10. 309597969055176 Received index 2 at 60 .30997681617737 Received index 3 at 110. 31065487861633 Received index 5 at 164 .84435486793518

    import Foundation
    import Combine
    
    let bounces:[(Int,TimeInterval)] = [
        (1, 10),
        (2, 20),
        (3, 60),
        (4, 70),
        (5, 110),
        (6, 120)
    ]
    
    var startTime = Date().timeIntervalSince1970
    let subject = PassthroughSubject<Int, Never>()
    var cancellable = subject
        .debounce(for: .seconds(50), scheduler: RunLoop.main)
        .sink { index in
            let offset = Date().timeIntervalSince1970 - startTime
            print ("Received index \(index) at \(offset)")
        }
    
    for bounce in bounces {
        DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) {
            subject.send(bounce.0)
        }
    }
    

    Received index 6 at 171 .00314784049988

    import Foundation
    import Combine
    
    let bounces:[(Int,TimeInterval)] = [
        (1, 10),
        (2, 20),
        (5, 110),
        (6, 120)
    ]
    
    var startTime = Date().timeIntervalSince1970
    let subject = PassthroughSubject<Int, Never>()
    var cancellable = subject
        .debounce(for: .seconds(50), scheduler: RunLoop.main)
        .sink { index in
            let offset = Date().timeIntervalSince1970 - startTime
            print ("Received index \(index) at \(offset)")
        }
    
    for bounce in bounces {
        DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) {
            subject.send(bounce.0)
        }
    }
    

    Received index 2 at 71. 99511885643005 Received index 6 at 170 .99344301223755

    enhancement 
    opened by okmyself 0
  • Consider mentioning the Exponential Backoff approach in

    Consider mentioning the Exponential Backoff approach in "retry" pattern

    The retry approach is described in https://heckj.github.io/swiftui-notes/#patterns-retry. In the exponential backoff approach, the delay differs each time (but not randomly :) ). An example of a possible implementation is here: https://peterfriese.dev/posts/swiftui-combine-custom-operators/

    I'm not sure if this request is appropriate, or is this case too specific. But in some of the apps I contributed to we used it (with an "imperative" non-reactive code).

    enhancement 
    opened by gatamar 0
  • Add illustrations for

    Add illustrations for "merge" & "zip" operators

    While the description of these operators is very good, it would be nice to have also the illustrations.

    Operators:

    • https://heckj.github.io/swiftui-notes/#reference-merge
    • https://heckj.github.io/swiftui-notes/#reference-zip

    Instructions:

    • swiftui-notes/marbles/README.md

    Output:

    • svg files added to swiftui-notes/docs/images/diagrams
    • reference.adoc file updated with a reference to an image
    • reference.adoc files updated for each localisation
    enhancement 
    opened by gatamar 2
  • Debounce, Throttle tests need to be broken up, potentially re-written

    Debounce, Throttle tests need to be broken up, potentially re-written

    The debounce and throttle tests are showing more and more differences between the CI system and running locally on my laptop with a simulator, vs. running on a device. Quite possibly I need to just bite the bullet and engage a TestScheduler mechanism here that's not effected by underlying system performace (Entwine) in order to make sure I'm getting accurate results, and on top of that the tests probably need to be broken out to be more easily consumable to anyone else reading them. I am finding them hard to parse when they break/change, so anyone else probably has it worse.

    enhancement 
    opened by heckj 1
  • update throttle to debounce in example

    update throttle to debounce in example

    Describe the solution you'd like Within https://heckj.github.io/swiftui-notes/#patterns-update-interface-userinput - the use of throttle is probably better advised as debounce - although both will work, debounce will probably work a touch better.

    enhancement 
    opened by heckj 0
  • `allSatisfy` description is misleading

    `allSatisfy` description is misleading

    I noticed that the section on allSatisfy says that the operator only publishes a value once the upstream publisher finishes. However, allSatisfy actually short-circuits in the same way containsWhere does, immediately publishing false and finishing once the predicate returns false.

    The Apple documentation does specify this behaviour:

    When this publisher receives an element, it runs the predicate against the element. If the predicate returns false, the publisher produces a false value and finishes. If the upstream publisher finishes normally, this publisher produces a true value and finishes.

    enhancement 
    opened by jayrhynas 1
Notes App using Core Data for persisting the data ✨

Notes Notes app where we can save and manage our daily notes. App usage The app allow us to add new notes We can delete our existing notes We can edit

Chris 0 Nov 13, 2021
MapApp - You can save the location of the places you go on the map and add names and notes

MapApp - You can save the location of the places you go on the map and add names and notes

Yağız Savran 3 Feb 1, 2022
FSNotes is modern notes manager for macOS and iOS.

FSNotes FSNotes is modern notes manager for macOS and iOS. macOS app Key features Markdown-first. Also supports any plaintext and RTF files. Fast and

null 5.3k Dec 29, 2022
ReleaseNotesKit - a brand new, elegant, and extremely simple way to present the recent version’s release notes to your users

ReleaseNotesKit This is ReleaseNotesKit, a brand new, elegant, and extremely simple way to present the recent version’s release notes to your users. R

Swapnanil Dhol 22 Jun 30, 2022
A functional, simplistic quick notes app, built in Swift for iOS

iOS QNApp Documentation Built for iOS 14 and above in XCode 13.1 Takes user input and stores in a note, can be modified at any time Dark mode and acce

itbarsoum 0 Jan 3, 2022
Africa application is developed for learning by using SwiftUI

Africa application is developed for learning by using swiftUI.This application show the list of animals along with information such as name,photo,description and video.This app also use map to show animals on map along with basic animation.

Ghullam Abbas 4 Oct 23, 2022
Learning SwiftUI by examples.

SwiftUI MindBlowing ?? Collections of mind-blowing SwiftUI snippets and projects. Why another awesome-swiftui? SwiftUI has come with a blast during an

An Tran 100 Nov 1, 2022
The SwiftUI learning project.

The SwiftUI learning project.

健了个平_(:з」∠)_ 9 Apr 28, 2022
VerticalTabView is a native way to display paged vertical content in SwiftUI.

VerticalTabView ?? VTabView is a native way to display paged vertical content in SwiftUI. To work it makes use of the new iOS 14 TabView PageTabViewSt

Lorenzo Fiamingo 25 Dec 16, 2022
Github repo search with using mvvm-c and clean architecture and using combine swift

GitSearchWithMVVM-C-CleanArchitecture Github repo search with using mvvm-c and clean architecture and using combine swift. Content Overview How To Run

Muhammad Qasim Majeed 1 Mar 16, 2022
iOS app that detects LaTeX symbols from drawings. Built using PencilKit, SwiftUI, Combine and CoreML for iOS 14 and macOS 11.

DeTeXt Finding the symbol you want to use in LaTeX can be hard since you can't memorize all the possible commands and packages for every symbol you mi

Venkat 73 Dec 8, 2022
small iOS & ipadOS application written in SwiftUI and Combine, that fetches twitter users and tweets using Twitter's api

HomeTwitter Small iOS & ipadOS application written in SwiftUI and Combine, that fetches twitter users and tweets using Twitter's api. This is just a s

Sorin Miroiu 1 May 13, 2022
Memorize - learning process from Standford University Swift UI videos

Memorize I am learning Swift UI. This app is in learning process from Standford

chitra 0 Jan 1, 2022
Learning App with Firebase Auth

Learning App Displays how to make a learning app with Swift, iOS's programming l

Andrew Gholson 0 Jan 9, 2022
An example APOD app with SwiftUI and Combine using NASA API

SwiftUI-APOD An example Astronomy Picture of the Day(APOD) application using SwiftUI and Combine under iOS 13 Requirement Xcode 11 macOS 10.15 Catalin

Liang Yi 22 Oct 16, 2022
This is an example project of SwiftUI and Combine using GitHub API.

SwiftUI-Combine-Example This is an example project of SwiftUI and Combine using GitHub GET /search/users API. ?? Requirements Swift5.1 Beta Xcode11.0

Ryo Aoyama 436 Jan 5, 2023
Paginated endless scroll using the SwiftUI and Combine frameworks

Article related to this project Infinite List Scroll with SwiftUI and Combine. InfiniteListSwiftUI A sample project showcasing how to build an infinit

Vadim Bulavin 69 Nov 16, 2022
Sample iOS project built by SwiftUI + Flux and Combine framework using GitHub API

SwiftUI-Flux Flux enables us to have unidirectional data flow and make it testable. It's used to be implemented using RxSwift or ReactiveSwift in the

Yusuke Kita 87 Nov 25, 2022
Sample iOS project built by SwiftUI + MVVM and Combine framework using GitHub API

SwiftUI-MVVM One of the biggest idea for having MVVM is that most of data flow can be testable. Data binding in view layer by SwiftUI is awesome. Howe

Yusuke Kita 592 Jan 2, 2023