epoxy-ios
Epoxy is a suite of declarative UI APIs for building UIKit applications in Swift
Top Related Projects
Valet lets you securely store data in the iOS, tvOS, or macOS Keychain without knowing a thing about how the Keychain works. It’s easy. We promise.
Elegant HTTP Networking in Swift
Reactive Programming in Swift
The better way to deal with JSON data in Swift.
A lightweight, pure-Swift library for downloading and caching images from the web.
A Swift Autolayout DSL for iOS & OS X
Quick Overview
Epoxy is an iOS library that simplifies the process of building complex screens with RecyclerView-like lists. It provides a declarative way to build and manage screens, making it easier to create and maintain complex user interfaces.
Pros
- Declarative UI: Epoxy uses a declarative approach to building UI, which makes it easier to reason about and maintain complex screens.
- Efficient Rendering: Epoxy automatically handles view recycling and diffing, which can improve the performance of your app.
- Modular Design: Epoxy encourages a modular design approach, where each component is self-contained and reusable.
- Testability: Epoxy's modular design makes it easier to write unit tests for your UI components.
Cons
- Learning Curve: Epoxy introduces a new way of thinking about UI development, which may have a steeper learning curve for developers who are more familiar with traditional imperative approaches.
- Overhead: Epoxy adds some overhead to your project, as it introduces additional abstractions and complexity.
- Dependency Management: Epoxy is a third-party library, which means you'll need to manage its dependency and updates in your project.
- Limited Documentation: The Epoxy documentation, while generally good, could be more comprehensive in some areas.
Code Examples
Here are a few examples of how to use Epoxy in your iOS project:
- Creating a Simple Model:
struct TextModel: EpoxyModel {
let text: String
var id: String { text }
func buildView(with controller: EpoxyController) -> UIView {
let label = UILabel()
label.text = text
return label
}
}
- Adding a Model to the Controller:
let controller = EpoxyController()
controller.setModels([
TextModel(text: "Hello, Epoxy!"),
TextModel(text: "This is another model.")
])
- Updating a Model:
controller.update(TextModel(text: "Updated text"))
- Handling Interactions:
struct ButtonModel: EpoxyModel {
let text: String
let action: () -> Void
var id: String { text }
func buildView(with controller: EpoxyController) -> UIView {
let button = UIButton()
button.setTitle(text, for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
return button
}
@objc private func buttonTapped() {
action()
}
}
Getting Started
To get started with Epoxy, follow these steps:
- Add the Epoxy dependency to your project using a package manager like CocoaPods or Carthage.
- Import the Epoxy framework in your Swift files:
import Epoxy
- Create your first Epoxy model by implementing the
EpoxyModel
protocol:
struct MyModel: EpoxyModel {
let text: String
var id: String { text }
func buildView(with controller: EpoxyController) -> UIView {
let label = UILabel()
label.text = text
return label
}
}
- Add your model to the Epoxy controller and render the view:
let controller = EpoxyController()
controller.setModels([MyModel(text: "Hello, Epoxy!")])
view.addSubview(controller.view)
- Explore the Epoxy documentation and sample projects to learn more about advanced features and best practices.
Competitor Comparisons
Valet lets you securely store data in the iOS, tvOS, or macOS Keychain without knowing a thing about how the Keychain works. It’s easy. We promise.
Pros of Valet
- Focused on secure data storage, providing a simple API for keychain access
- Supports synchronization across devices via iCloud Keychain
- Lightweight and easy to integrate into existing projects
Cons of Valet
- Limited in scope compared to Epoxy's comprehensive UI framework
- Lacks UI components and declarative UI building capabilities
- May require additional libraries for complex UI development
Code Comparison
Valet (Storing data securely):
let myValet = Valet.valet(with: Identifier(nonEmpty: "Secrets")!, accessibility: .whenUnlocked)
try? myValet.setString("12345", forKey: "PIN")
let retrievedPIN = try? myValet.string(forKey: "PIN")
Epoxy (Building UI components):
struct MyView: EpoxyableView {
var body: some View {
VStack {
Text("Hello, Epoxy!")
Button("Tap me") { /* action */ }
}
}
}
Summary
Valet focuses on secure data storage using the iOS Keychain, while Epoxy is a comprehensive UI framework for building complex user interfaces. Valet is ideal for projects requiring simple and secure data management, whereas Epoxy is better suited for large-scale UI development with reusable components and declarative syntax.
Elegant HTTP Networking in Swift
Pros of Alamofire
- Widely adopted and battle-tested networking library for iOS
- Comprehensive feature set for HTTP networking, including request/response handling, authentication, and parameter encoding
- Extensive documentation and community support
Cons of Alamofire
- Focused solely on networking, while Epoxy offers a more comprehensive UI development solution
- May introduce unnecessary complexity for simple networking tasks
- Requires additional libraries or custom code for UI-related functionality
Code Comparison
Alamofire (HTTP request):
AF.request("https://api.example.com/data").responseJSON { response in
switch response.result {
case .success(let value):
print("Success: \(value)")
case .failure(let error):
print("Error: \(error)")
}
}
Epoxy (UI component):
final class MyView: UIView, EpoxyableView {
let titleLabel = UILabel()
func setContent(_ content: String, state: ViewState) {
titleLabel.text = content
}
}
While Alamofire excels in networking tasks, Epoxy focuses on declarative UI development. Alamofire is ideal for projects requiring robust HTTP functionality, whereas Epoxy shines in creating complex, reusable UI components. The choice between the two depends on the specific needs of your iOS project.
Reactive Programming in Swift
Pros of RxSwift
- Powerful reactive programming paradigm for handling asynchronous events and data streams
- Extensive ecosystem with many extensions and libraries
- Strong community support and regular updates
Cons of RxSwift
- Steeper learning curve, especially for developers new to reactive programming
- Can lead to complex code if not used carefully
- Potential performance overhead for simple use cases
Code Comparison
RxSwift:
Observable.from([1, 2, 3, 4, 5])
.filter { $0 % 2 == 0 }
.map { $0 * 2 }
.subscribe(onNext: { print($0) })
Epoxy:
dataSource.setSections([
Section(items: [
ItemModel(dataID: "1", content: .init(title: "Item 1")),
ItemModel(dataID: "2", content: .init(title: "Item 2"))
])
])
RxSwift focuses on reactive streams and transformations, while Epoxy is designed for declarative UI composition. RxSwift's code demonstrates chaining operations on an observable sequence, whereas Epoxy's example shows how to define a data source for UI components. The choice between the two depends on the specific requirements of your project and your team's familiarity with reactive programming concepts.
The better way to deal with JSON data in Swift.
Pros of SwiftyJSON
- Lightweight and focused solely on JSON parsing
- Easy to use with a simple, chainable syntax
- Extensive error handling and type safety
Cons of SwiftyJSON
- Limited to JSON parsing, unlike Epoxy's broader UI component management
- May require additional libraries for more complex data handling
- Less actively maintained compared to Epoxy
Code Comparison
SwiftyJSON:
let json = JSON(data: dataFromNetworking)
if let name = json["user"]["name"].string {
// Do something with name
}
Epoxy:
struct MySection: EpoxyableSection {
var epoxyItems: [EpoxyableModel] {
return [
DataRow(title: "Name", value: user.name)
]
}
}
Key Differences
- SwiftyJSON focuses on JSON parsing, while Epoxy is a UI component framework
- Epoxy provides a more comprehensive solution for building complex UIs
- SwiftyJSON is more suitable for simple data handling tasks
- Epoxy offers better performance for large-scale applications with many UI components
Use Cases
SwiftyJSON is ideal for:
- Quick JSON parsing in small to medium-sized projects
- Prototyping and rapid development
Epoxy is better suited for:
- Building complex, data-driven UIs
- Large-scale iOS applications with numerous reusable components
- Projects requiring high performance and scalability
A lightweight, pure-Swift library for downloading and caching images from the web.
Pros of Kingfisher
- Focused specifically on image downloading and caching, making it more lightweight and efficient for this use case
- Extensive image processing capabilities, including resizing, blurring, and color adjustments
- Supports multiple sources for image loading, including URLs, local files, and data objects
Cons of Kingfisher
- Limited to image-related functionality, unlike Epoxy's broader UI component management
- May require additional libraries or custom code for complex UI layouts and animations
- Less suitable for building entire view hierarchies or managing complex data-driven UIs
Code Comparison
Kingfisher (image loading):
let imageView = UIImageView()
imageView.kf.setImage(with: URL(string: "https://example.com/image.jpg"))
Epoxy (UI component):
let component = ImageComponent(
image: .url(URL(string: "https://example.com/image.jpg")!),
size: .init(width: 100, height: 100)
)
While both libraries can handle image loading, Kingfisher provides a more straightforward API for this specific task. Epoxy, on the other hand, offers a more comprehensive approach to building UI components, which may be beneficial for larger, more complex applications.
A Swift Autolayout DSL for iOS & OS X
Pros of SnapKit
- Simpler and more lightweight, focusing solely on Auto Layout constraints
- Easier to learn and use for developers familiar with Auto Layout concepts
- More flexible for creating custom layouts without predefined components
Cons of SnapKit
- Limited to constraint-based layouts, lacking higher-level abstractions
- Requires more manual work for complex UI structures and data binding
- Less suitable for large-scale applications with numerous reusable components
Code Comparison
SnapKit:
view.snp.makeConstraints { make in
make.top.equalTo(superview.snp.top).offset(20)
make.left.right.equalTo(superview).inset(16)
make.height.equalTo(44)
}
Epoxy:
GroupModel(
dataID: "header",
items: [
TextRowModel(
dataID: "title",
text: "Hello, World!",
style: .title
)
]
)
SnapKit focuses on creating constraints programmatically, while Epoxy provides a higher-level abstraction for building complex UI components and managing their data. SnapKit is more suitable for smaller projects or custom layouts, whereas Epoxy excels in large-scale applications with reusable components and complex data flows.
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
Epoxy is a suite of declarative UI APIs for building UIKit applications in Swift. Epoxy is inspired and influenced by the wonderful Epoxy framework on Android, as well as other declarative UI frameworks in Swift such as SwiftUI.
Epoxy was developed at Airbnb and powers thousands of screens in apps that are shipped to millions of users. It has been developed and refined for years by dozens of contributors.
Below are a few sample screens from the Airbnb app that we've built using Epoxy. Our usages of Epoxy span from our simplest forms and static screens to our most advanced and dynamic features.
Home Details | Home Photos | Messaging | Registration |
---|---|---|---|
Table of contents
Installation
Epoxy can be installed using CocoaPods or Swift Package Manager.
CocoaPods
To get started with Epoxy using Cocoapods add the following to your Podfile
and then follow the integration instructions.
pod 'Epoxy'
Epoxy is separated into podspecs for each module so you only have to include what you need.
Swift Package Manager (SPM)
To install Epoxy using Swift Package Manager you can follow the tutorial published by Apple using the URL for the Epoxy repo with the current version:
- In Xcode, select âFileâ â âSwift Packagesâ â âAdd Package Dependencyâ
- Enter https://github.com/airbnb/epoxy-ios.git
Epoxy is separated library products for each module so you only have to include what you need.
Modules
Epoxy has a modular architecture so you only have to include what you need for your use case:
Module | Description |
---|---|
Epoxy | Includes all of the below modules in a single import statement |
EpoxyCollectionView | Declarative API for driving the content of a UICollectionView |
EpoxyNavigationController | Declarative API for driving the navigation stack of a UINavigationController |
EpoxyPresentations | Declarative API for driving the modal presentations of a UIViewController |
EpoxyBars | Declarative API for adding fixed top/bottom bar stacks to a UIViewController |
EpoxyLayoutGroups | Declarative API for building composable layouts in UIKit with a syntax similar to SwiftUI's stack APIs |
EpoxyCore | Foundational APIs that are used to build all Epoxy declarative UI APIs |
Documentation and tutorials
For full documentation and step-by-step tutorials please check the wiki. For type-level documentation, see the Epoxy DocC documentation hosted on the Swift Package Index.
There's also a full sample app with a lot of examples that you can either run via the EpoxyExample
scheme in Epoxy.xcworkspace
or browse its source.
If you still have questions, feel free to create a new issue.
Getting started
EpoxyCollectionView
EpoxyCollectionView
provides a declarative API for driving the content of a UICollectionView
. CollectionViewController
is a subclassable UIViewController
that lets you easily spin up a UICollectionView
-backed view controller with a declarative API.
The following code samples will render a single cell in a UICollectionView
with a TextRow
component rendered in that cell. TextRow
is a simple UIView
containing two labels that conforms to the EpoxyableView
protocol.
You can either instantiate a CollectionViewController
instance directly with sections, e.g. this view controller with a selectable row:
Source | Result |
|
Or you can subclass CollectionViewController
for more advanced scenarios, e.g. this view controller that keeps track of a running count:
Source | Result |
|
You can learn more about EpoxyCollectionView
in its wiki entry, or by browsing the code documentation.
EpoxyBars
EpoxyBars
provides a declarative API for rendering fixed top, fixed bottom, or input accessory bar stacks in a UIViewController
.
The following code example will render a ButtonRow
component fixed to the bottom of the UIViewController
's view. ButtonRow
is a simple UIView
component that contains a single UIButton
constrained to the margins of the superview that conforms to the EpoxyableView
protocol:
Source | Result |
|
You can learn more about EpoxyBars
in its wiki entry, or by browsing the code documentation.
EpoxyNavigationController
EpoxyNavigationController
provides a declarative API for driving the navigation stack of a UINavigationController
.
The following code example shows how you can use this to easily drive a feature that has a flow of multiple view controllers:
Source | Result |
|
You can learn more about EpoxyNavigationController
in its wiki entry, or by browsing the code documentation.
EpoxyPresentations
EpoxyPresentations
provides a declarative API for driving the modal presentation of a UIViewController
.
The following code example shows how you can use this to easily drive a feature that shows a modal when it first appears:
Source | Result |
|
You can learn more about EpoxyPresentations
in its wiki entry, or by browsing the code documentation.
EpoxyLayoutGroups
LayoutGroups are UIKit Auto Layout containers inspired by SwiftUI's HStack
and VStack
that allow you to easily compose UIKit elements into horizontal and vertical groups.
VGroup
allows you to group components together vertically to create stacked components like this:
Source | Result |
|
As you can see, this is incredibly similar to the other APIs used in Epoxy. One important thing to note is that install(in: view)
call at the bottom. Both HGroup
and VGroup
are written using UILayoutGuide
which prevents having large nested view hierarchies. To account for this, weâve added this install
method to prevent the user from having to add subviews and the layout guide manually.
Using HGroup
is almost exactly the same as VGroup
but the components are now horizontally laid out instead of vertically:
Source | Result |
|
Groups support nesting too, so you can easily create complex layouts with multiple groups:
Source | Result |
|
You can learn more about EpoxyLayoutGroups
in its wiki entry, or by browsing the code documentation.
FAQ
- Why would I use Epoxy and UIKit instead of SwiftUI?
- How does Epoxy for iOS differ from Epoxy for Android?
Contributing
Pull requests are welcome! We'd love help improving this library. Feel free to browse through open issues to look for things that need work. If you have a feature request or bug, please open a new issue so we can track it. Contributors are expected to follow the Code of Conduct.
License
Epoxy is released under the Apache License 2.0. See LICENSE
for details.
Credits
Logo design by Alana Hanada and Jonard La Rosa
Top Related Projects
Valet lets you securely store data in the iOS, tvOS, or macOS Keychain without knowing a thing about how the Keychain works. It’s easy. We promise.
Elegant HTTP Networking in Swift
Reactive Programming in Swift
The better way to deal with JSON data in Swift.
A lightweight, pure-Swift library for downloading and caching images from the web.
A Swift Autolayout DSL for iOS & OS X
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