Top Related Projects
Reactive Programming in Swift
Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.
Network abstraction layer written in Swift.
A Swift Reactive Programming Kit
Quick Overview
Bond is a cross-platform framework for working with schematized data. It supports efficient serialization and deserialization, and is designed to be fast, compact, and versatile. Bond is particularly useful for scenarios involving cross-language serialization or communication between heterogeneous systems.
Pros
- High performance and efficient serialization
- Cross-platform and multi-language support (C++, C#, Java, Python)
- Flexible schema evolution, allowing for backward and forward compatibility
- Compact binary format, reducing data size and network traffic
Cons
- Steeper learning curve compared to simpler serialization libraries
- Limited community support and resources compared to more popular alternatives
- Requires additional tooling for schema compilation
- May be overkill for simple serialization needs
Code Examples
- Defining a Bond schema:
namespace example
struct Person
{
0: string name;
1: uint16 age;
2: vector<string> hobbies;
}
- Serializing data in C++:
#include <bond/core/bond.h>
#include <bond/stream/output_buffer.h>
using namespace example;
Person person;
person.name = "Alice";
person.age = 30;
person.hobbies.push_back("reading");
person.hobbies.push_back("hiking");
bond::OutputBuffer output;
bond::CompactBinaryWriter<bond::OutputBuffer> writer(output);
bond::Serialize(person, writer);
- Deserializing data in C#:
using Bond;
using Bond.Protocols;
using Bond.IO.Safe;
var input = new InputBuffer(serializedData);
var reader = new CompactBinaryReader<InputBuffer>(input);
var person = Bond.Deserialize<Person>.From(reader);
Console.WriteLine($"Name: {person.name}, Age: {person.age}");
Getting Started
-
Install Bond:
- For C++: Use vcpkg or build from source
- For C#: Install via NuGet:
Install-Package Bond.CSharp
- For Python:
pip install bond
-
Define your schema in a .bond file
-
Compile the schema:
gbc c++ --output=. my_schema.bond
-
Include generated files in your project and start using Bond for serialization and deserialization
Competitor Comparisons
Reactive Programming in Swift
Pros of RxSwift
- More comprehensive and feature-rich, offering a wider range of operators and functionalities
- Larger community and ecosystem, providing better support and resources
- Cross-platform compatibility with other Rx implementations
Cons of RxSwift
- Steeper learning curve due to its complexity and extensive API
- Potentially higher memory footprint and performance overhead
- Can lead to overuse of reactive paradigms, making code harder to understand
Code Comparison
RxSwift:
Observable.from([1, 2, 3, 4, 5])
.filter { $0 % 2 == 0 }
.map { $0 * 2 }
.subscribe(onNext: { print($0) })
Bond:
let numbers = Observable<[Int]>([1, 2, 3, 4, 5])
numbers
.map { $0.filter { $0 % 2 == 0 }.map { $0 * 2 } }
.observeNext { print($0) }
Both libraries provide reactive programming capabilities for Swift, but RxSwift offers a more extensive set of features and better cross-platform compatibility. Bond, on the other hand, focuses on simplicity and ease of use, making it a good choice for smaller projects or developers new to reactive programming. The code comparison shows that both libraries have similar syntax for basic operations, but RxSwift's approach is more granular and chainable.
Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.
Pros of ReactiveCocoa
- More mature and widely adopted in the iOS community
- Supports a broader range of reactive programming concepts
- Offers more advanced features like schedulers and error handling
Cons of ReactiveCocoa
- Steeper learning curve due to its complexity
- Heavier framework with more overhead
- Less focused on Swift-specific features and syntax
Code Comparison
ReactiveCocoa:
let disposable = textField.reactive.continuousTextValues
.map { text in text.uppercased() }
.bind(to: label.reactive.text)
Bond:
let disposable = textField.reactive.text
.map { $0.uppercased() }
.bind(to: label.reactive.text)
Summary
ReactiveCocoa is a more comprehensive reactive programming framework with a longer history in the iOS ecosystem. It offers a wider range of features and concepts, making it suitable for complex reactive programming scenarios. However, this comes at the cost of increased complexity and a steeper learning curve.
Bond, on the other hand, is more focused on Swift-specific reactive programming, offering a simpler and more lightweight approach. It may be easier to adopt for developers new to reactive programming or those working on smaller projects that don't require the full feature set of ReactiveCocoa.
Both frameworks provide similar basic functionality, as seen in the code comparison, but ReactiveCocoa's API tends to be more verbose and feature-rich.
Network abstraction layer written in Swift.
Pros of Moya
- Focused specifically on network abstraction, providing a clean and robust API for handling network requests
- Extensive documentation and community support, making it easier for developers to get started and troubleshoot issues
- Built-in support for stubbing network requests, facilitating easier testing and development
Cons of Moya
- Limited to networking tasks, whereas Bond offers a broader range of reactive programming features
- May introduce additional complexity for simple networking tasks that don't require such a comprehensive framework
- Steeper learning curve for developers new to reactive programming concepts
Code Comparison
Moya example:
let provider = MoyaProvider<MyAPI>()
provider.request(.userProfile) { result in
switch result {
case let .success(response):
let data = response.data
// Handle the response
case let .failure(error):
// Handle the error
}
}
Bond example:
let observable = Observable<String>("Initial value")
observable.bind(to: label.bnd_text)
observable.value = "New value"
While Moya focuses on network requests, Bond provides a more general-purpose reactive programming framework. Moya excels in API abstraction and network-related tasks, while Bond offers a wider range of reactive programming capabilities for various aspects of iOS development.
A Swift Reactive Programming Kit
Pros of ReactiveKit
- More lightweight and focused on core reactive programming concepts
- Provides a more flexible and extensible architecture
- Better suited for advanced reactive programming scenarios
Cons of ReactiveKit
- Steeper learning curve for beginners
- Less comprehensive UI binding capabilities out of the box
- Requires more manual setup for common UI interactions
Code Comparison
ReactiveKit:
let signal = Signal<Int, Never>()
signal.observeNext { value in
print("Received value: \(value)")
}
signal.send(value: 42)
Bond:
let observable = Observable<Int>(0)
observable.bind(to: label.bnd_text)
observable.value = 42
ReactiveKit focuses on core reactive programming concepts, offering a more flexible architecture for advanced scenarios. However, it has a steeper learning curve and requires more manual setup for UI interactions. Bond, on the other hand, provides more comprehensive UI binding capabilities out of the box, making it easier for beginners to get started with reactive programming in iOS development.
The code comparison demonstrates the difference in approach between the two libraries. ReactiveKit uses signals and observers, while Bond utilizes observables and bindings, showcasing their distinct philosophies in implementing reactive programming concepts.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Bond, Swift Bond
Update: Bond 7 has been released! Check out the migration guide to learn more about the update.
Bond is a Swift binding framework that takes binding concepts to a whole new level. It's simple, powerful, type-safe and multi-paradigm - just like Swift.
Bond is built on top of ReactiveKit and bridges the gap between the reactive and imperative paradigms. You can use it as a standalone framework to simplify your state changes with bindings and reactive data sources, but you can also use it with ReactiveKit to complement your reactive data flows with bindings, reactive delegates and reactive data sources.
Bond is a backbone of the Binder Architecture - a preferred architecture to be used with the framework.
Why use Bond?
Say that you would like to do something when text of a text field changes. Well, you could setup the target-action mechanism between your objects and go through all that target-action selector registration pain, or you could simply use Bond and do this:
textField.reactive.text.observeNext { text in
print(text)
}
Now, instead of printing what the user has typed, you can bind it to a label:
textField.reactive.text.bind(to: label.reactive.text)
Because binding to a label text property is so common, you can even do:
textField.reactive.text.bind(to: label)
That one line establishes a binding between the text field's text property and label's text property. In effect, whenever user makes a change to the text field, that change will automatically be propagated to the label.
More often than not, direct binding is not enough. Usually you need to transform input is some way, like prepending a greeting to a name. As Bond is backed by ReactiveKit it has full confidence in functional paradigm.
textField.reactive.text
.map { "Hi " + $0 }
.bind(to: label)
Whenever a change occurs in the text field, new value will be transformed by the closure and propagated to the label.
Notice how we have used reactive.text
property of the text field. It is an observable representation of the text
property provided by Bond framework. There are many other extensions like that one for various UIKit components. They are all placed within the .reactive
proxy.
For example, to observe button events do:
button.reactive.controlEvents(.touchUpInside)
.observeNext { e in
print("Button tapped.")
}
Handling touchUpInside
event is used so frequently that Bond comes with the extension just for that event:
button.reactive.tap
.observeNext {
print("Button tapped.")
}
You can use any ReactiveKit operators to transform or combine signals. Following snippet depicts how values of two text fields can be reduced to a boolean value and applied to button's enabled property.
combineLatest(emailField.reactive.text, passField.reactive.text) { email, pass in
return email.length > 0 && pass.length > 0
}
.bind(to: button.reactive.isEnabled)
Whenever user types something into any of these text fields, expression will be evaluated and button state updated.
Bond's power is not, however, in coupling various UI components, but in the binding of the business logic layer (i.e. Service or View Model) to the View layer and vice-versa. Here is how one could bind user's number of followers property of the model to the label.
viewModel.numberOfFollowers
.map { "\($0)" }
.bind(to: label)
Point here is not in the simplicity of a value assignment to the text property of a label, but in the creation of a binding which automatically updates label text property whenever the number of followers change.
Bond also supports two way bindings. Here is an example of how you could keep username text field and username property of your View Model in sync (whenever any of them change, other one will be updated too):
viewModel.username
.bidirectionalBind(to: usernameTextField.reactive.text)
Bond is also great for observing various different events and asynchronous tasks. For example, you could observe a notification like this:
NotificationCenter.default.reactive.notification("MyNotification")
.observeNext { notification in
print("Got \(notification)")
}
.dispose(in: bag)
Let me give you one last example. Say you have an array of repositories you would like to display in a collection view. For each repository you have a name and its owner's profile photo. Of course, photo is not immediately available as it has to be downloaded, but once you get it, you want it to appear in collection view's cell. Additionally, when user does 'pull down to refresh' and your array gets new repositories, you want those in collection view too.
So how do you proceed? Well, instead of implementing a data source object, observing photo downloads with KVO and manually updating the collection view with new items, with Bond you can do all that in just few lines:
repositories.bind(to: collectionView) { array, indexPath, collectionView in
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! RepositoryCell
let repository = array[indexPath.item]
repository.name
.bind(to: cell.nameLabel)
.dispose(in: cell.onReuseBag)
repository.photo
.bind(to: cell.avatarImageView)
.dispose(in: cell.onReuseBag)
return cell
}
Yes, that's right!
Reactive Extensions
Bond is all about bindings and other reactive extensions. To learn more about how bindings work and how to create your own bindings check out the documentation on bindings.
If you are interested in what bindings and extensions are supported, just start typing .reactive.
on any UIKit or AppKit object and you will get the list of available extensions. You can also skim over the source files to get an overview.
Observable Collections
When working with arrays usually we need to know how exactly did an array change. New elements could have been inserted into the array and old ones deleted or updated. Bond provides mechanisms for observing such fine-grained changes.
For example, Bond provides you with a (Mutable)ObservableArray
type that can be used to generate and observe fine-grained changes.
let names = MutableObservableArray(["Steve", "Tim"])
...
names.observeNext { e in
print("array: \(e.collection), diff: \(e.diff), patch: \(e.patch)")
}
You work with the observable array like you would work with the array it encapsulates.
names.append("John") // prints: array: ["Steve", "Tim", "John"], diff: Inserts: [2], patch: [I(John, at: 2)]
names.removeLast() // prints: array: ["Steve", "Tim"], diff: Deletes: [2], patch: [D(at: 2)]
names[1] = "Mark" // prints: array: ["Steve", "Mark"], diff: Updates: [1], patch: [U(at: 1, newElement: Mark)]
Peek into observable collections documentation to learn more about observable collections.
Data Source Signals
Observable collections and other data source signals enable us to build powerful UI bindings. For example, an observable array can be bound to a collection view just like this:
names.bind(to: collectionView, cellType: UserCell.self) { (cell, name) in
cell.titleLabel.text = name
}
No need to implement data source objects and do everything manually. Check out documentation on the data source signals to learn more about them and about table or collection view bindings.
Protocol Proxies
Bond provides NSObject
extensions that make it easy to convert delegate method calls into signal. The extensions are built on top of ObjC runtime and enable you to intercept delegate method invocations and convert them into signal events.
Bond uses protocol proxies to implement table and collection view bindings and to provide signals like tableView.reactive.selectedRowIndexPath
. Check out the protocol proxies documentation to learn more.
Community Extensions
Make sure to check out Extensions directory. It contains extensions that make Bond easy to use with other frameworks and libraries, like Realm.
If you have an extensions that makes your favourite framework work with Bond and you'd like to share it with everyone, we'd be more than happy to accept your PR.
Requirements
- iOS 8.0+ / macOS 10.11+ / tvOS 9.0+
- Swift 4.2
Communication
- If you'd like to ask a question, open an issue.
- If you found a bug, open an issue.
- If you have a feature request, open an issue.
- If you want to contribute, submit a pull request (include unit tests).
Installation
Carthage
-
Add the following to your Cartfile:
github "DeclarativeHub/Bond"
-
Run
carthage update
-
Add the framework as described in Carthage Readme
Accio
-
Add the following to your Package.swift:
.package(url: "https://github.com/DeclarativeHub/Bond.git", .upToNextMajor(from: "7.4.1")),
-
Next, add
Bond
to your App targets dependencies like so:.target( name: "App", dependencies: [ "Bond", ] ),
-
Then run
accio update
.
CocoaPods
-
Add the following to your Podfile:
pod 'Bond'
-
Run
pod install
.
License
The MIT License (MIT)
Copyright (c) 2015-2019 Srdan Rasic (@srdanrasic)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Top Related Projects
Reactive Programming in Swift
Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.
Network abstraction layer written in Swift.
A Swift Reactive Programming Kit
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot