Simple, lightweight swift bindings

Overview

Awesome Build status Version License Platform

Bindy

Just a simple bindings.

Installation

Add pod 'Bindy'

to your podfile, and run pod install

SPM is supported too.

Usage

For now, Bindy has a couple of basic types

  • Signal - allows triggering a callback when some signal received.
  • Observable - allows observing changing of value.
  • ObservableArray - conforms to MutableCollection protocol, so you can work with it like with a regular array: subscript index, replace objects, map, enumerate, etc... Also, ObservableArray has updates signal, which will notify you about any changes in the array, such as insert, replace, delete.

Observables Sample (updated with property wrappers)

@Observable var firstname = "Salvador"
@Observable var age = 54

func setupBindings() {
    $age.bind(self) { [unowned self] newAge in
            print("Happy \(newAge) birthday, \(firstname)")
    }
    age = 55
}

Don't forget always use [unowned owner] in closure to prevent the retain cycle.

Signal and Array Sample

let messages: ObservableArray<Message> = []
let newMessage = Signal<Message>()
    
func setupBindings() {
    newMessage.bind(self) { [unowned self] message in
            self.messages.append(message)
    }
    
    messages.updates.bind(self) { [unowned tableView] updates in
            self.tableView.pefrom(updates: updates)     
       }
}
       
func handleDidRecieveMessage(_ message: Message) {
     newMessage.send(message)      
    }
}

You don't need to remove binding manually if you don't want. When the object that you pass as owner in bind(_ owner: AnyObject... method deallocates, corresponding bindings will clean. However, if you want to unbind manually, just call unbind(_ owner: AnyObject). Bindy has an extension for tableView for performing updates tableView.perform(updates:...

Also, observables have a method observe(_ owner: AnyObject..., it works like bind, but triggers callback immediately, this may be more comfortable in some situations.

Transformations

If you want to receive events with transformed type, you can use transform function on Observables like:

let speed = Observable(20)
lazy var speedString = speed.transform { "\($0)km/h" }
    
func setupBindings() {
    speedString.observe(self) { [unowned self] speedString in
        // speedString = "20km/h"
            self.speedLabel.text = speedString
        }
}

Combinations

You can combine two Observable types with combined(with: ..., transform: ...) function like:

let firstname = Observable("Maxim")
let lastname = Observable("Kotliar")
let age = Observable(24)

lazy var fullName = firstname
            .combined(with: lastname) { "name: \($0) \($1)" }
            .combined(with: age) { "\($0), age: \($1)" }

func setupBindings() {
    userInfo.observe(self) { [unowned self] info in
            // info = "name: Maxim Kotliar, age:24"
            self.userInfoLabel.text = info
        }
}

For Observable<Bool> combinations Bindy have more convenient operators && and ||, so you can combine Observable<Bool> like regular Bool, also you can invert it with !:

let isPremiumPurchased = Observable(true)
let isInTrialPeriodEnded = Observable(false)
let isAdsShowForced = Observable(false)

lazy var shouldShowAds = isAdsShowForced || !isPremiumPurchased && isInTrialPeriodEnded

KVO support

Bindy supports KVO, so you can create Observable from any KVO capable property with easy subscript syntax like:

let textField = UITextField()
let text = textField[\.text] // type will be Observable<String?>

text.observe(self) { newText in
    print(newText)
}

Old value

For any Observable type you can receive old value in closure, just pass two parameters to binding closure, first one will be an old value, the second one – new value:

let observableString = Observable("test")

observableString.bind(self) { oldString, newString in
    print("String changed from \(oldString) to \(newString)")
}

High order functions

Bindy contains some high order functions:

  • map - applies on any type, behavior similar to a swift map.
  • flatMap - applies on Observable with optional type, returns Signal with non-optional type.
  • compactMap - applies on Observable with Collection inside, behavior similar to a swift version of the function.
  • reduce - applies on Observable with Collection inside, behavior similar to a swift version of the function.
  • filter - applies on Observable with Collection inside, behavior similar to a swift version of the function.
You might also like...
A super simple library for state management with unidirectional data flow.
A super simple library for state management with unidirectional data flow.

OneWay 🚧 OneWay is still experimental. As such, expect things to break and change in the coming months. OneWay is a super simple library for state ma

A Simple exemple of a launching screen made of 100% using SwuiftUI.
A Simple exemple of a launching screen made of 100% using SwuiftUI.

A Simple exemple of a launching screen made of 100% using SwuiftUI. You can modify and use it in your app Compatible from iOS 14 (older not tested ) to iOS 16 (beta tested only )

Redux for Swift - a predictable state container for Swift apps

Merge / deprecation announcement: ReduxKit and Swift-Flow have joined forces! The result is ReSwift. The nitty gritty: We decided to deprecate ReduxKi

Unidirectional flow implemented using the latest Swift Generics and Swift Concurrency features.

swift-unidirectional-flow Unidirectional flow implemented using the latest Swift Generics and Swift Concurrency features. struct SearchState: Equatabl

Reactive Programming in Swift
Reactive Programming in Swift

Rx is a generic abstraction of computation expressed through ObservableElement interface, which lets you broadcast and subscribe to values and other

RxSwift extentions for Swift optionals and "Occupiable" types

RxOptional RxSwift extentions for Swift optionals and "Occupiable" types. Usage All operators are available on Driver as well unless otherwise marked.

Unidirectional Data Flow in Swift - Inspired by Redux
Unidirectional Data Flow in Swift - Inspired by Redux

ReSwift Supported Swift Versions: Swift 4.2, 5.x For Swift 3.2 or 4.0 Support use Release 5.0.0 or earlier. For Swift 2.2 Support use Release 2.0.0 or

A Swift Reactive Programming Kit
A Swift Reactive Programming Kit

ReactiveKit is a lightweight Swift framework for reactive and functional reactive programming that enables you to get into the reactive world today. T

RxSwift wrapper around the elegant HTTP networking in Swift Alamofire

RxAlamofire RxAlamofire is a RxSwift wrapper around the elegant HTTP networking in Swift Alamofire. Getting Started Wrapping RxSwift around Alamofire

Comments
  • Migrating from v0.1.8  & OptionalObservable

    Migrating from v0.1.8 & OptionalObservable

    I inherited a code base using Bindy 0.1.8 and wanted to update to the latest version. I'm getting an error that OptionalObservable doesn't exist. Is the best way of handling this to declare a regular Observable make the generic type an optional? For example:

    eg. OptionalObservable < Date > ( nil ) ==> Observable< Date? >(nil)

    opened by philosopherdog 0
  • Extend readme

    Extend readme

    There are some unexplained features in readme like:

    • [x] transform
    • [x] combine
    • [x] combine bool through && and. ||
    • [ ] UIKit extensions
    • [ ] reduce, throttle...
    • [ ] attachables
    • [ ] WatchOS Support
    • [ ] Property wrapper
    enhancement 
    opened by MaximKotliar 0
Releases(0.3.3)
Owner
Maxim Kotliar
iOS/macOS Developer
Maxim Kotliar
Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.

Reactive extensions to Cocoa frameworks, built on top of ReactiveSwift. ⚠️ Looking for the Objective-C API? ?? Migrating from RAC 4.x? ?? Release Road

null 20k Jan 8, 2023
RxSwift bindings for Permissions API in iOS.

RxPermission RxSwift bindings for Permission API that helps you with Permissions in iOS. Installation RxPermission is available through CocoaPods. I c

Luke 230 Dec 27, 2022
Animated RxCocoa bindings

RxAnimated - animated bindings RxAnimated provides animation interface to RxCocoa's bindings. It comes with few predefined animation bindings, and pro

RxSwift Community 687 Oct 26, 2022
Simple and lightweight Functional Reactive Coding in Swift for the rest of us

The simplest Observable<T> implementation for Functional Reactive Programming you will ever find. This library does not use the term FRP (Functional R

Jens Ravens 1.1k Jan 3, 2023
RxReduce is a lightweight framework that ease the implementation of a state container pattern in a Reactive Programming compliant way.

About Architecture concerns RxReduce Installation The key principles How to use RxReduce Tools and dependencies Travis CI Frameworks Platform Licence

RxSwift Community 125 Jan 29, 2022
📬 A lightweight implementation of an observable sequence that you can subscribe to.

Features Lightweight Observable is a simple implementation of an observable sequence that you can subscribe to. The framework is designed to be minima

Felix M. 133 Aug 17, 2022
A lightweight, event-driven architectural framework

Trellis Trellis features a declarative DSL that simplifies service bootstrapping: let cluster = try await Bootstrap { Group { Store(model:

Valentin Radu 25 Aug 16, 2022
A lightweight Elm-like Store for SwiftUI

ObservableStore A simple Elm-like Store for SwiftUI, based on ObservableObject. ObservableStore helps you craft more reliable apps by centralizing all

Subconscious 28 Nov 8, 2022
Super Simple Pager with RxSwift extension

SSPager Super Simple Pager Example To run the example project, clone the repo, and run pod install from the SSPagerExample directory first. Installati

9oya 4 Jul 10, 2022
UIKitPreviews - A simple way to see your UIKit ViewController changes live and on-demand

SwiftUI preview provider for UIKit A simple way to see your UIKit ViewController

Emad Beyrami 8 Jan 8, 2023