{"id":13462689,"url":"https://github.com/airbnb/epoxy-ios","last_synced_at":"2025-05-15T07:03:51.109Z","repository":{"id":37943332,"uuid":"152341224","full_name":"airbnb/epoxy-ios","owner":"airbnb","description":"Epoxy is a suite of declarative UI APIs for building UIKit applications in Swift","archived":false,"fork":false,"pushed_at":"2024-10-08T23:39:52.000Z","size":6698,"stargazers_count":1275,"open_issues_count":10,"forks_count":75,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-05-15T07:03:42.377Z","etag":null,"topics":["ios","swift","uicollectionview","uikit","uinavigationcontroller"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/airbnb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-10T00:54:13.000Z","updated_at":"2025-05-15T01:36:58.000Z","dependencies_parsed_at":"2024-03-02T00:28:23.515Z","dependency_job_id":"56cbfd27-0b2f-447f-932b-51e351a3e805","html_url":"https://github.com/airbnb/epoxy-ios","commit_stats":{"total_commits":575,"total_committers":57,"mean_commits":"10.087719298245615","dds":0.5895652173913044,"last_synced_commit":"158193d731d4cc1616fc465d331af64c6b7df594"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airbnb%2Fepoxy-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airbnb%2Fepoxy-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airbnb%2Fepoxy-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airbnb%2Fepoxy-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/airbnb","download_url":"https://codeload.github.com/airbnb/epoxy-ios/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254291962,"owners_count":22046425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","swift","uicollectionview","uikit","uinavigationcontroller"],"created_at":"2024-07-31T13:00:18.958Z","updated_at":"2025-05-15T07:03:51.085Z","avatar_url":"https://github.com/airbnb.png","language":"Swift","funding_links":[],"categories":["Uncategorized","Swift","UI Component"],"sub_categories":["Uncategorized"],"readme":"\u003cimg  width=\"300\" alt=\"Epoxy logo\" src=\"docs/images/logo.svg\" \u003e\n\n[![Build Status](https://github.com/airbnb/epoxy-ios/workflows/CI/badge.svg?branch=master)](https://github.com/airbnb/epoxy-ios/actions?query=branch%3Amaster+workflow%3ACI)\n[![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://github.com/apple/swift-package-manager)\n[![Platform](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fairbnb%2Fepoxy-ios%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/airbnb/epoxy-ios)\n[![Swift Versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fairbnb%2Fepoxy-ios%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/airbnb/epoxy-ios)\n\nEpoxy is a suite of declarative UI APIs for building [UIKit](https://developer.apple.com/documentation/uikit) applications in Swift. Epoxy is inspired and influenced by the wonderful [Epoxy framework on Android](https://github.com/airbnb/epoxy), as well as other declarative UI frameworks in Swift such as [SwiftUI](https://developer.apple.com/documentation/swiftui).\n\nEpoxy was developed at [Airbnb](https://www.airbnb.com/) 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](https://github.com/airbnb/epoxy-ios/graphs/contributors).\n\nBelow 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.\n| Home Details | Home Photos | Messaging | Registration |\n| --- | --- | --- | --- |\n| ![Home Details](docs/images/home_details.png) | ![Home Photos](docs/images/home_photos.png)  | ![Messaging](docs/images/messaging.png) | ![Registration](docs/images/registration.png) |\n\n## Table of contents\n\n* [Installation](#installation)\n    * [CocoaPods](#cocoapods)\n    * [Swift Package Manager (SPM)](#swift-package-manager-spm)\n* [Modules](#modules)\n* [Documentation and tutorials](#documentation-and-tutorials)\n* [Getting started](#getting-started)\n    * [EpoxyCollectionView](#epoxycollectionview)\n    * [EpoxyBars](#epoxybars)\n    * [EpoxyNavigationController](#epoxynavigationcontroller)\n    * [EpoxyPresentations](#epoxypresentations)\n    * [EpoxyLayoutGroups](#epoxylayoutgroups)\n* [FAQ](#faq)\n* [Contributing](#contributing)\n* [License](#license)\n* [Credits](#credits)\n\n## Installation\n\nEpoxy can be installed using [CocoaPods](#CocoaPods) or [Swift Package Manager](#Swift-Package-Manager-(SPM)).\n\n### CocoaPods\n\nTo get started with Epoxy using [Cocoapods](https://cocoapods.org) add the following to your `Podfile` and then follow the [integration instructions](https://guides.cocoapods.org/using/using-cocoapods.html).\n\n```ruby\npod 'Epoxy'\n```\n\nEpoxy is separated into [podspecs](https://guides.cocoapods.org/syntax/podspec.html) for each [module](#modules) so you only have to include what you need.\n\n### Swift Package Manager (SPM)\n\nTo install Epoxy using [Swift Package Manager](https://github.com/apple/swift-package-manager)  you can follow the [tutorial published by Apple](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) using the URL for the Epoxy repo with the current version:\n\n1. In Xcode, select “File” → “Swift Packages” → “Add Package Dependency”\n1. Enter https://github.com/airbnb/epoxy-ios.git\n\nEpoxy is separated [library products](https://swift.org/package-manager/#products) for each [module](#modules) so you only have to include what you need.\n\n## Modules\n\nEpoxy has a modular architecture so you only have to include what you need for your use case:\n\n| Module | Description |\n| ------ | ----------- |\n| [`Epoxy`](https://github.com/airbnb/epoxy-ios/blob/master/Sources/Epoxy/Exports.swift) | Includes all of the below modules in a single import statement |\n| [`EpoxyCollectionView`](#EpoxyCollectionView) | Declarative API for driving the content of a [`UICollectionView`](https://developer.apple.com/documentation/uikit/uicollectionview) |\n| [`EpoxyNavigationController`](#EpoxyNavigationController) | Declarative API for driving the navigation stack of a [`UINavigationController`](https://developer.apple.com/documentation/uikit/uinavigationcontroller) |\n| [`EpoxyPresentations`](#EpoxyPresentations) | Declarative API for driving the modal presentations of a [`UIViewController`](https://developer.apple.com/documentation/uikit/uiviewcontroller) |\n| [`EpoxyBars`](#EpoxyBars) | Declarative API for adding fixed top/bottom bar stacks to a [`UIViewController`](https://developer.apple.com/documentation/uikit/uiviewcontroller) |\n| [`EpoxyLayoutGroups`](#EpoxyLayoutGroups) | Declarative API for building composable layouts in UIKit with a syntax similar to SwiftUI's stack APIs |\n| [`EpoxyCore`](https://github.com/airbnb/epoxy-ios/wiki/EpoxyCore) | Foundational APIs that are used to build all Epoxy declarative UI APIs |\n\n## Documentation and tutorials\n\nFor full documentation and step-by-step tutorials please check the [wiki](https://github.com/airbnb/epoxy-ios/wiki). For type-level documentation, see the [Epoxy DocC documentation](https://swiftpackageindex.com/airbnb/epoxy-ios/master/documentation/epoxycore) hosted on the [Swift Package Index](https://swiftpackageindex.com/).\n\nThere'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](https://github.com/airbnb/epoxy-ios/tree/master/Example).\n\nIf you still have questions, feel free to create a new [issue](https://github.com/airbnb/epoxy-ios/issues).\n\n## Getting started\n\n### EpoxyCollectionView\n\n`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.\n\nThe 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`](https://github.com/airbnb/epoxy-ios/wiki/EpoxyCore#views) protocol.\n\nYou can either instantiate a `CollectionViewController` instance directly with sections, e.g. this view controller with a selectable row:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nenum DataID {\n  case row\n}\n\nlet viewController = CollectionViewController(\n  layout: UICollectionViewCompositionalLayout\n    .list(using: .init(appearance: .plain)),\n  items: {\n    TextRow.itemModel(\n      dataID: DataID.row,\n      content: .init(title: \"Tap me!\"),\n      style: .small)\n      .didSelect { _ in\n        // Handle selection\n      }\n  })\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg width=\"250\" alt=\"Screenshot\" src=\"docs/images/tap_me_example.png\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nOr you can subclass `CollectionViewController` for more advanced scenarios, e.g. this view controller that keeps track of a running count:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nclass CounterViewController: CollectionViewController {\n  init() {\n    let layout = UICollectionViewCompositionalLayout\n      .list(using: .init(appearance: .plain))\n    super.init(layout: layout)\n    setItems(items, animated: false)\n  }\n\n  enum DataID {\n    case row\n  }\n\n  var count = 0 {\n    didSet {\n      setItems(items, animated: true)\n    }\n  }\n\n  @ItemModelBuilder\n  var items: [ItemModeling] {\n    TextRow.itemModel(\n      dataID: DataID.row,\n      content: .init(\n        title: \"Count \\(count)\",\n        body: \"Tap to increment\"),\n      style: .large)\n      .didSelect { [weak self] _ in\n        self?.count += 1\n      }\n  }\n}\n```\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg width=\"250\" alt=\"Screenshot\" src=\"docs/images/counter_example.gif\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nYou can learn more about `EpoxyCollectionView` in its [wiki entry](https://github.com/airbnb/epoxy-ios/wiki/EpoxyCollectionView), or by browsing the [code documentation](https://swiftpackageindex.com/airbnb/epoxy-ios/master/documentation/epoxycollectionview).\n\n### EpoxyBars\n\n`EpoxyBars` provides a declarative API for rendering fixed top, fixed bottom, or [input accessory](https://developer.apple.com/documentation/uikit/uiresponder/1621119-inputaccessoryview) bar stacks in a `UIViewController`.\n\nThe 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`](https://github.com/airbnb/epoxy-ios/wiki/EpoxyCore#views) protocol:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nclass BottomButtonViewController: UIViewController {\n  override func viewDidLoad() {\n    super.viewDidLoad()\n    bottomBarInstaller.install()\n  }\n\n  lazy var bottomBarInstaller = BottomBarInstaller(\n    viewController: self,\n    bars: bars)\n\n  @BarModelBuilder\n  var bars: [BarModeling] {\n    ButtonRow.barModel(\n      content: .init(text: \"Click me!\"),\n      behaviors: .init(didTap: {\n        // Handle button selection\n      }))\n  }\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg width=\"250\" alt=\"Screenshot\" src=\"docs/images/bottom_button_example.png\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nYou can learn more about `EpoxyBars` in its [wiki entry](https://github.com/airbnb/epoxy-ios/wiki/EpoxyBars), or by browsing the [code documentation](https://swiftpackageindex.com/airbnb/epoxy-ios/master/documentation/epoxybars).\n\n### EpoxyNavigationController\n\n`EpoxyNavigationController` provides a declarative API for driving the navigation stack of a `UINavigationController`.\n\nThe following code example shows how you can use this to easily drive a feature that has a flow of multiple view controllers:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nclass FormNavigationController: NavigationController {\n  init() {\n    super.init()\n    setStack(stack, animated: false)\n  }\n\n  enum DataID {\n    case step1, step2\n  }\n\n  var showStep2 = false {\n    didSet {\n      setStack(stack, animated: true)\n    }\n  }\n\n  @NavigationModelBuilder\n  var stack: [NavigationModel] {\n    .root(dataID: DataID.step1) { [weak self] in\n      Step1ViewController(didTapNext: {\n        self?.showStep2 = true\n      })\n    }\n\n    if showStep2 {\n      NavigationModel(\n        dataID: DataID.step2,\n        makeViewController: {\n          Step2ViewController(didTapNext: {\n            // Navigate away from this step.\n          })\n        },\n        remove: { [weak self] in\n          self?.showStep2 = false\n        })\n    }\n  }\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg width=\"250\" alt=\"Screenshot\" src=\"docs/images/form_navigation_example.gif\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nYou can learn more about `EpoxyNavigationController` in its [wiki entry](https://github.com/airbnb/epoxy-ios/wiki/EpoxyNavigationController), or by browsing the [code documentation](https://swiftpackageindex.com/airbnb/epoxy-ios/master/documentation/epoxynavigationcontroller).\n\n### EpoxyPresentations\n\n`EpoxyPresentations` provides a declarative API for driving the modal presentation of a `UIViewController`.\n\nThe following code example shows how you can use this to easily drive a feature that shows a modal when it first appears:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nclass PresentationViewController: UIViewController {\n  override func viewDidAppear(_ animated: Bool) {\n    super.viewDidAppear(animated)\n    setPresentation(presentation, animated: true)\n  }\n\n  enum DataID {\n    case detail\n  }\n\n  var showDetail = true {\n    didSet {\n      setPresentation(presentation, animated: true)\n    }\n  }\n\n  @PresentationModelBuilder\n  var presentation: PresentationModel? {\n    if showDetail {\n      PresentationModel(\n        dataID: DataID.detail,\n        presentation: .system,\n        makeViewController: { [weak self] in\n          DetailViewController(didTapDismiss: {\n            self?.showDetail = false\n          })\n        },\n        dismiss: { [weak self] in\n          self?.showDetail = false\n        })\n    }\n  }\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg width=\"250\" alt=\"Screenshot\" src=\"docs/images/modal_example.gif\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nYou can learn more about `EpoxyPresentations` in its [wiki entry](https://github.com/airbnb/epoxy-ios/wiki/EpoxyPresentations), or by browsing the [code documentation](https://swiftpackageindex.com/airbnb/epoxy-ios/master/documentation/epoxypresentations).\n\n## EpoxyLayoutGroups\n\nLayoutGroups are UIKit [Auto Layout](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html) containers inspired by SwiftUI's [`HStack`](https://developer.apple.com/documentation/swiftui/hstack) and [`VStack`](https://developer.apple.com/documentation/swiftui/vstack) that allow you to easily compose UIKit elements into horizontal and vertical groups.\n\n`VGroup` allows you to group components together vertically to create stacked components like this:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\n// Set of dataIDs to have consistent\n// and unique IDs\nenum DataID {\n  case title\n  case subtitle\n  case action\n}\n\n// Groups are created declaratively\n// just like Epoxy ItemModels\nlet group = VGroup(\n  alignment: .leading,\n  spacing: 8)\n{\n  Label.groupItem(\n    dataID: DataID.title,\n    content: \"Title text\",\n    style: .title)\n  Label.groupItem(\n    dataID: DataID.subtitle,\n    content: \"Subtitle text\",\n    style: .subtitle)\n  Button.groupItem(\n    dataID: DataID.action,\n    content: \"Perform action\",\n    behaviors: .init { button in\n      print(\"Button tapped! \\(button)\")\n    },\n    style: .standard)\n}\n\n// install your group in a view\ngroup.install(in: view)\n\n// constrain the group like you\n// would a normal subview\ngroup.constrainToMargins()\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg alt=\"ActionRow screenshot\" src=\"docs/images/ActionRow.png\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nAs 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`](https://developer.apple.com/documentation/uikit/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.\n\nUsing `HGroup` is almost exactly the same as `VGroup` but the components are now horizontally laid out instead of vertically:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nenum DataID {\n  case icon\n  case title\n}\n\nlet group = HGroup(spacing: 8) {\n  ImageView.groupItem(\n    dataID: DataID.icon,\n    content: UIImage(systemName: \"person.fill\")!,\n    style: .init(size: .init(width: 24, height: 24)))\n  Label.groupItem(\n    dataID: DataID.title,\n    content: \"This is an IconRow\")\n}\n\ngroup.install(in: view)\ngroup.constrainToMargins()\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg alt=\"IconRow screenshot\" src=\"docs/images/IconRow.png\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nGroups support nesting too, so you can easily create complex layouts with multiple groups:\n\n\u003ctable\u003e\n\u003ctr\u003e\u003ctd\u003e Source \u003c/td\u003e \u003ctd\u003e Result \u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```swift\nenum DataID {\n  case checkbox\n  case titleSubtitleGroup\n  case title\n  case subtitle\n}\n\nHGroup(spacing: 8) {\n  Checkbox.groupItem(\n    dataID: DataID.checkbox,\n    content: .init(isChecked: true),\n    style: .standard)\n  VGroupItem(\n    dataID: DataID.titleSubtitleGroup,\n    style: .init(spacing: 4))\n  {\n    Label.groupItem(\n      dataID: DataID.title,\n      content: \"Build iOS App\",\n      style: .title)\n    Label.groupItem(\n      dataID: DataID.subtitle,\n      content: \"Use EpoxyLayoutGroups\",\n      style: .subtitle)\n  }\n}\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n\u003cimg alt=\"IconRow screenshot\" src=\"docs/images/CheckboxRow.png\"\u003e\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nYou can learn more about `EpoxyLayoutGroups` in its [wiki entry](https://github.com/airbnb/epoxy-ios/wiki/EpoxyLayoutGruops), or by browsing the [code documentation](https://swiftpackageindex.com/airbnb/epoxy-ios/master/documentation/epoxylayoutgroups).\n\n## FAQ\n\n- [Why would I use Epoxy and UIKit instead of SwiftUI?](https://github.com/airbnb/epoxy-ios/wiki/FAQ#why-would-i-use-epoxy-and-uikit-instead-of-swiftui)\n- [How does Epoxy for iOS differ from Epoxy for Android?](https://github.com/airbnb/epoxy-ios/wiki/FAQ#how-does-epoxy-for-ios-differ-from-epoxy-for-android)\n\n## Contributing\n\nPull requests are welcome! We'd love help improving this library. Feel free to browse through open [issues](https://github.com/airbnb/epoxy-ios/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](./CODE_OF_CONDUCT.md).\n\n## License\n\nEpoxy is released under the Apache License 2.0. See `LICENSE` for details.\n\n## Credits\nLogo design by [Alana Hanada](https://twitter.com/AlanaHanada) and [Jonard La Rosa](https://twitter.com/NotJoNacho)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fairbnb%2Fepoxy-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fairbnb%2Fepoxy-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fairbnb%2Fepoxy-ios/lists"}