• Stars
    star
    116
  • Rank 303,894 (Top 6 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 3 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

XUI makes modular, testable architectures for SwiftUI apps a breeze!

XUI Logo

XUI is a toolbox for creating modular, reusable, testable app architectures with SwiftUI. With extensions to tackle common issues, XUI makes working with SwiftUI and Combine a lot easier!

  • Easily keep your apps clean, maintainable and with a consistent app state
  • Abstract view models with protocols
  • Make more use of common SwiftUI and Combine components
  • Find any object in deep hierarchies

In our blog articles

we have already had a look at how to organize views and view models in SwiftUI. With all this knowledge, we have combined and summarized the most important and useful components in this library.

๐Ÿ”ฅ Features

  • Abstraction of view models with protocols through the use of the @Store property wrapper
  • Deep Linking made easy โ†’ simply find any coordinator or view model in your app with a single call!
  • Useful extensions to make the use of SwiftUI and Combine simpler!

๐Ÿƒโ€โ™‚๏ธGetting Started

Store

One of the integral parts of XUI is the Store property wrapper. It makes it possible to define SwiftUI view models with protocols.

Let me guide you through the process: First, we create a protocol for our view model and make that conform to ViewModel.

import XUI

protocol MyViewModel: ViewModel {

    // You can specify properties and methods as you like
    // This is just an example
    
    var text: String { get set }
    
    func open()
    
}

Secondly, we create an implementation for that protocol. Our implementation needs to be a class conforming to ObservableObject and our protocol.

import XUI

class DefaultMyViewModel: MyViewModel, ObservableObject {

    @Published var text: String
    
    func open() {
        // ...
    } 

}

Last but not least, we use the Store property wrapper to use a protocol as view model in our view.

import XUI

struct MyView: View {
    @Store var viewModel: MyViewModel
    
    var body: some View {
        TextField("Text", text: $viewModel.text)
    }
}

As you can see, you can use your view model as you would with the @ObservedObject property wrapper in SwiftUI. Instead of being constrained to a concrete type, you can specify a protocol instead. This way, we can write different implementations of the MyViewModel protocol and use them in MyView as well.

Deep Links

For deep links, we provide a search algorithm throughout your view model / coordinator hierarchy. You can use the DeepLinkable protocol to provide access to your immediate children. To find a specific child in that hierarchy, you can use the firstReceiver method on DeepLinkable.

You can find a more extensive explanation in this blog article.

๐Ÿคธโ€โ™‚๏ธ Extensions

XUI makes working with Combine and SwiftUI a lot easier!

Cancellable

When working with Combine extensively, there might be many occurences of .store(in: &cancellables) in your code. To minimize code size and make code a bit more readable, we offer a function builder to insert multiple Cancellables in a collection at once. Let's see it in action:

var cancellables = Set<AnyCancellable>()

cancellables.insert {
    $myViewModel.title
        .sink { print("MyViewModel title changed to", $0) }

    $myViewModel.text
        .sink { print("MyViewModel text changed to", $0) }
}

Publisher

With Publishers, you often work with singles or simply publishers that will only emit a single value or an error. To make working with these publishers easier (and since the Result type is part of Swift now), we can simply build the following extensions:

var publisher: AnyPublisher<String, MyError>

publisher.asResult() // AnyPublisher<Result<String, MyError>, Never>
publisher.mapResult(success: { $0 }, failure: { _ in "Error occured." }) // AnyPublisher<String, Never>
publisher.tryMapResult(success: { $0 }, failure: { throw $0 }) // AnyPublisher<String, Error>

ViewModifiers

When using the Coordinator Pattern in SwiftUI (as discussed in this blog article), we need to inject a view modifier into a child view, so that transition logic is fully specified by the coordinator view rather than being distributed across views.

NavigationModifier, PopoverModifier and SheetModifier are provided, with a similar interface to the actual modifiers.

View

To make working with NavigationView simpler in SwiftUI, we provide a onNavigation method that can be used, when you would like a closure to be performed, when a NavigationLink is performed. Simply put it around your view, it will add a NavigationLink itself.

Further, we add methods to your views for handling sheet, popover and navigation with view model protocols.

Example:

struct MyView: View {
    
    @Store var viewModel: MyViewModel
    
    var body: some View {
        NavigationView {
            Text("Example")
                .navigation(model: $viewModel.detailViewModel) { viewModel in
                    DetailView(viewModel: viewModel)
                }
                .sheet(model: $viewModel.sheetViewModel) { viewModel in
                    SheetView(viewModel: viewModel)
                }
        }
    }
    
}

Binding

Working with bindings, especially when it concerns collections is hard - but no longer! We have written a few extensions to easily work with elements of collections using bindings.

var binding: Binding<[String]>

binding.first(equalTo: "example") // Binding<String?>
binding.first(where: { $0.count < 5 }) // Binding<String?>, this is not a practical example though

binding.first(equalTo: "example").forceUnwrap() // Binding<String>
binding.first(equalTo: "example").force(as: CustomStringConvertible.self) // Binding<CustomStringConvertible>

Further, one would possibly like to alter or observe the values being used through a binding.

var binding: Binding<String>

binding.willSet { print("will set", $0) } 
// Binding<String>, will print whenever a new value is set by the binding, before it is forwarded to the initial binding

binding.didSet { print("did set", $0) } 
// Binding<String>, will print whenever a new value is set by the binding, after it is forwarded to the initial binding

binding.ensure { !$0.isEmpty }
// Binding<String>, will only set the initial binding, when the condition is fulfilled

binding.assert { !$0.isEmpty }
// Binding<String>, will assert on get and set, that a condition is fulfilled

binding.map(get: { $0.first! }, set: { String($0) })
// Binding<String>, will map the binding's value to a different type

binding.alterGet { $0.prefix(1) } 
// Binding<String>, will forward the altered value on get

binding.alterSet { $0.prefix(1) } 
// Binding<String>, will forward the altered value on set to the underlying binding

๐Ÿ“š Example

As an example on how to use XUI in your application, we have written a Recipes App with the help of XUI.

๐Ÿ›  Installation

Swift Package Manager

See this WWDC presentation about more information how to use Swift packages in your app. Specify https://github.com/quickbirdstudios/XUI.git as the XUI package link.

๐Ÿ‘จโ€๐Ÿ’ป Author

This framework is created with โค๏ธ by QuickBird Studios.

๐Ÿค Contributing

Open an issue if you need help, if you found a bug, or if you want to discuss a feature request. Open a PR if you want to make changes to XUI.

๐Ÿ“ƒ License

XUI is released under an MIT license. See License.md for more information.

More Repositories

1

XCoordinator

๐ŸŽŒ Powerful navigation library for iOS based on the coordinator pattern
Swift
2,253
star
2

FlippingNotch

FlippingNotch ๐Ÿค™ - Dribble inspired animation https://dribbble.com/shots/4089014-Pull-To-Refresh-iPhone-X
Swift
835
star
3

SwiftUI-Architectures

Three different architectures (Model-View, Redux, MVVM) for using SwiftUI implemented at the example of a chat app
Swift
682
star
4

opencv-android

Easy way to integrate OpenCv into your Android project via Gradle
Kotlin
673
star
5

PullToReach

PullToReach is a simple drag-and-drop solution for adding pull-to-reach functionality to your app
Swift
516
star
6

SurveyKit

Android library to create beautiful surveys (aligned with ResearchKit on iOS)
Kotlin
386
star
7

SwiftUI-Coordinators-Example

Sample app that showcases the use of the Coordinator Pattern in SwiftUI
Swift
223
star
8

CombineRxSwiftPerformance

A test suite comparing the performance of Combine and RxSwift
Swift
187
star
9

survey_kit

Flutter library to create beautiful surveys (aligned with ResearchKit on iOS)
Dart
124
star
10

XCoordinator-Example

XCoordinator-Example serves as an MVVM-C example app for XCoordinator
Swift
64
star
11

kotlin-snapshot-testing

Extensible Kotlin Multiplatform library to easily create Snapshot tests for Android and other Kotlin applications
Kotlin
61
star
12

XServiceLocator

Light-weight Service Locator / Dependency Injection library for Swift: providing objects with the dependencies they need throughout your whole iOS app.
Swift
54
star
13

yuvToMat

High-performance library for converting YUV_420_888 Android Camera images to OpenCV RGB Mats
Kotlin
53
star
14

NonEmptyCollections

A type-safe implementation for collections that cannot be empty. Life is too short for emptiness-checks!
Kotlin
53
star
15

DataKit

A Swift library to easily read and write binary formatted data using a modern, declarative interface.
Swift
42
star
16

flutter_platform_search

A platform-adaptive search for Flutter
Dart
36
star
17

flutter_pull_to_reach_demo

A new way to access controls in your flutter app that are normally hard to reach with your thumb
Dart
26
star
18

QBRepository

QBRepository is a simple implementation of the repository pattern for data access in Swift
Swift
16
star
19

DependencyInjectionPlayground

Playground showing different techniques for dependency injection in Swift
Swift
15
star
20

platform-independent-mvvm-android

An Android-MVVM example of how we create platform-independent ViewModels that can be reused on iOS/Desktop/Server
Kotlin
13
star
21

crc-swift

Swift
11
star
22

XCoordinator-Talks

Presentations & Workshops about the Coordinator pattern & XCoordinator
Swift
6
star
23

crc-kotlin

Kotlin
5
star
24

DoggyKotlinKoans

A list of entertaining koans/exercises to learn the basic features of Kotlin (including solutions).
Kotlin
3
star
25

mobile_hacknight_flutter

Dart
3
star
26

actions

JavaScript
2
star
27

HackNight-SwiftUI

Swift
1
star