SkillAgentSearch skills...

Cleanse

Lightweight Swift Dependency Injection Framework

Install / Use

/learn @square/Cleanse
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

[Deprecated] Cleanse - Swift Dependency Injection

.. image:: Documentation/cleanse_logo_small.png :align: right

.. image:: https://travis-ci.org/square/Cleanse.svg?branch=master :target: https://travis-ci.org/square/Cleanse

.. image:: https://coveralls.io/repos/github/square/Cleanse/badge.svg?branch=master&asdf :target: https://coveralls.io/github/square/Cleanse?branch=master

Cleanse is a dependency injection_ framework for Swift. It is designed from the ground-up with developer experience in mind. It takes inspiration from both Dagger_ and Guice_.

.. _dependency injection: https://en.wikipedia.org/wiki/Dependency_injection .. _Guice: https://github.com/google/guice .. _Dagger: http://google.github.io/dagger/

Deprecation Notice:

Dear Cleanse Community,

We are announcing that the Cleanse repository will be officially deprecated as of June 13th, 2024. Over the years, Cleanse has aimed to provide a robust solution for Swift dependency injection, and we are incredibly grateful for the support and contributions from our community.

This decision is based on Square's decision to use a different dependency injection framework. We believe this step will allow us to focus our efforts on other projects and innovations that better serve the needs of our users and the broader open-source ecosystem.

What This Means for You

- **No Further Updates**: There will be no further updates, bug fixes, or new features added to Cleanse.
- **Repository Status**: The repository will remain available in a read-only state for historical reference and for those who may still find value in the existing codebase.
- **Support**: We will no longer provide active support or respond to issues and pull requests.

Recommended Alternatives

We encourage you to fork this repo, or explore the following alternatives that may better meet your needs:

  • Needle_
  • Swinject_
  • Weaver_
  • Factory_
  • PointFree's Dependencies_

.. _Needle: https://github.com/uber/needle .. _Swinject: https://github.com/Swinject/Swinject .. _Weaver: https://github.com/scribd/Weaver .. _Factory: https://github.com/hmlongco/Factory .. _PointFree's Dependencies: https://github.com/pointfreeco/swift-dependencies

Contact us

If you have interest in maintaining this repo, or have any other inquiries, please reach out to us at opensource+external@squareup.com.

Thank You

We extend our heartfelt thanks to everyone who has contributed to Cleanse, whether through code, documentation, or community support. Your efforts have been invaluable and deeply appreciated. Thank you for being a part of the Cleanse journey.

Sincerely, The Cleanse Team at Square

Getting Started

This is a quick guide on how to get started using Cleanse in your application.

A full-fledged example of using Cleanse with Cocoa Touch can be found in Examples/CleanseGithubBrowser

Installation

Using `CocoaPods`_
~~~~~~~~~~~~~~~~~~~
You can pull in the latest Cleanse version into your ``Podfile`` using

``pod 'Cleanse'``

.. _CocoaPods: https://github.com/cocoapods/cocoapods/

Using Xcode
~~~~~~~~~~~
``Cleanse.xcodeproj`` can be dragged and dropped into an existing project or workspace in Xcode.
One may add ``Cleanse.framework`` as a target dependency and embed it.

Using `Carthage`_
~~~~~~~~~~~~~~~~~
Cleanse should be able to be configured with `Carthage`_. One should be able to follow the
`Adding Frameworks to an Application`_ from `Carthage's README`_ to successfully do this.

.. _Adding Frameworks to an Application: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
.. _Carthage's README: https://github.com/Carthage/Carthage/blob/master/README.md
.. _Carthage: https://github.com/Carthage/Carthage/

Using `Swift Package Manager`_
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Cleanse can be used with `Swift Package Manager`_. The following a definition that can be added to the dependencies 
of a ``Project`` declaration. Adding `Cleanse` as a package dependency in Xcode 11 is supported by v4.2.5 and above.

.. _Swift Package Manager: https://github.com/apple/swift-package-manager

Features
--------
=================================== =================================
   Feature                          Cleanse Implementation Status
=================================== =================================
Multi-Bindings                      Supported (``.intoCollection()``)
Overrides                           Supported
Objective-C Compatibility layer     Supported
Property Injection [#pinj]_         Supported
Type Qualifiers                     Supported via `Type Tags`_
`Assisted Injection`_               Supported
`Subcomponents`_                    Supported via `Components`_
`Service Provider Interface`_       Supported
`cleansec`_ (Cleanse Compiler)      Experimental
=================================== =================================

.. [#pinj] Property injection is known as `field injection`_ in other DI frameworks

.. _Subcomponents: http://google.github.io/dagger/subcomponents.html
.. _cleansec: https://github.com/square/Cleanse/tree/master/cleansec
.. _field injection: https://github.com/google/guice/wiki/Injections#field-injection

Another very important part of a DI framework is how it handles errors. Failing fast is ideal. Cleanse is designed to
support fast failure. It currently supports fast failing for some of the more common errors, but it isn't complete

=================================== =================================
   Error Type                       Cleanse Implementation Status
=================================== =================================
Missing Providers                   Supported [#f1]_
Duplicate Bindings                  Supported
Cycle Detection                     Supported
=================================== =================================

.. [#f1] When a provider is missing, errors present line numbers, etc. where the provider was required. Cleanse
        will also collect all errors before failing

Using Cleanse

The Cleanse API is in a Swift module called Cleanse (surprised?). To use any of its API in a file, at the top, one must import it.

.. code-block:: swift

import Cleanse

Defining a Component and Root Type

Cleanse is responsible for building a graph (or more specifically a `directed acyclic graph`_) that represents all of your dependencies.
This graph starts with a root object which is connected to its immediate dependencies, and those dependencies hold edges to its dependencies and so on until we have a complete picture of your application's object graph.

.. _`directed acyclic graph`: https://en.wikipedia.org/wiki/Directed_acyclic_graph

The entry point into managing your dependencies with Cleanse starts by defining a "Root" object that is returned to you upon construction. In a Cocoa Touch application, our root object could be the ``rootViewController`` object we set on the application's ``UIWindow``. *(More logically the root object is the App Delegate, however since we don't control construction of that we would have to use Property Injection. You can read more about this in the* `Advanced Setup`_ *guide)*

Let's begin by defining the ``RootComponent``:


.. code-block:: swift

  struct Component : Cleanse.RootComponent {
      // When we call build(()) it will return the Root type, which is a RootViewController instance.
      typealias Root = RootViewController

      // Required function from Cleanse.RootComponent protocol.
      static func configureRoot(binder bind: ReceiptBinder<RootViewController>) -> BindingReceipt<RootViewController> {

      }

      // Required function from Cleanse.RootComponent protocol.
      static func configure(binder: Binder<Unscoped>) {
          // We will fill out contents later.
      }
  }

After creating our root component, we find that we're required to implement two functions:
``static func configureRoot(binder bind: ReceiptBinder<RootViewController>) -> BindingReceipt<RootViewController>`` and ``static func configure(binder: Binder<Unscoped>)``. These functions are very important because they will contain the logic for how we construct every object/dependency in our app. The parameters and return types are confusing right now, but will make more sense as we go along.

The first function is required of any `Component` since it tells Cleanse how to construct the root object. Let's fill in the contents to configure how we will construct our ``RootViewController``.

.. code-block:: swift

  static func configureRoot(binder bind: ReceiptBinder<RootViewController>) -> BindingReceipt<RootViewController> {
      return bind.to(factory: RootViewController.init)
  }


Now, let's create our ``RootViewController`` class

.. code-block:: swift

  class RootViewController: UIViewController {
      init() {
          super.init(nibName: nil, bundle: nil)
      }

      required init?(coder aDecoder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }

      override func viewDidLoad() {
          super.viewDidLoad()
          self.view.backgroundColor = .blue
      }
  }


We've successfully wired up our root component! Our root object ``RootViewController`` is configured properly, so in our App Delegate we can now `build` the component (and graph) to use it.

**Important**: It is important that you retain an instance of the `ComponentFactory<E>` returned from `ComponentFactory.of(:)`. Otherwise subcomponents may unexpectedly become deallocated.

.. code-block:: swift

    // IMPORTANT: We must retain an instance of our `ComponentFactory`.
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        var factory: ComponentFactory<AppDelegate.Component>?

        func application(application: UIApplication, didFinishLaunchingWithOptions la
View on GitHub
GitHub Stars1.8k
CategoryDevelopment
Updated10d ago
Forks82

Languages

Swift

Security Score

85/100

Audited on Mar 19, 2026

No findings