Swiftpack.co - Package - uber/needle

Build Status Carthage compatible License

Needle is a dependency injection (DI) system for Swift. Unlike other DI frameworks, such as Cleanse, Swinject, Needle encourages hierarchical DI structure and utilizes code generation to ensure compile-time safety. This allows us to develop our apps and make code changes with confidence. If it compiles, it works. In this aspect, Needle is more similar to Dagger for the JVM.

Needle aims to achieve the following primary goals:

  1. Provide high reliability by ensuring dependency injection code is compile-time safe.
  2. Ensure code generation is highly performant even when used with multi-million-line codebases.
  3. Be compatible with all iOS application architectures, including RIBs, MVx etc.

The gist

Using Needle to write DI code for your application is easy and compile-time safe. Each dependency scope is defined by a Component. And its dependencies are encapsulated in a Swift protocol. The two are linked together using Swift generics.

/// This protocol encapsulates the dependencies acquired from ancestor scopes.
protocol MyDependency: Dependency {
    /// These are objects obtained from ancestor scopes, not newly introduced at this scope.
    var chocolate: Food { get }
    var milk: Food { get }
}

/// This class defines a new dependency scope that can acquire dependencies from ancestor scopes
/// via its dependency protocol, provide new objects on the DI graph by declaring properties,
/// and instantiate child scopes.
class MyComponent: Component<MyDependency> {

    /// A new object, hotChocolate, is added to the dependency graph. Child scope(s) can then
    /// acquire this via their dependency protocol(s).
    var hotChocolate: Drink {
        return HotChocolate(dependency.chocolate, dependency.milk)
    }

    /// A child scope is always instantiated by its parent(s) scope(s).
    var myChildComponent: MyChildComponent {
        return MyChildComponent(parent: self)
    }
}

This is pretty much it, when writing DI code with Needle. As you can see, everything is real, compilable Swift code. No fragile comments or "annotations". To quickly recap, the three key concepts here are dependency protocol, component and instantiation of child component(s). Please refer to the Getting started with Needle section below for more detailed explanations and advanced topics.

Getting started with Needle

Using and integrating with Needle has two steps. Each of the following steps has detailed instructions and explanations in the linked documents.

  1. Integrate Needle's code generator with your Swift project.
  2. Write application DI code following NeedleFoundation's API.

Installation

Needle has two parts, the NeedleFoundation framework and the executable code generator. Both parts need to be integrated with your Swift project in order to use Needle as your DI system.

Install NeedleFoundation framework

Using Carthage

Please follow the standard Carthage installation process to integrate the NeedleFoundation framework with your Swift project.

github "https://github.com/uber/needle.git" ~> VERSION_OF_NEEDLE

Using Swift Package Manager

Please specify Needle as a dependency via the standard Swift Package Manager package definition process to integrate the NeedleFoundation framework with your Swift project.

dependencies: [
    .package(url: "https://github.com/uber/needle.git", .upToNextMajor(from: "VERSION_NUMBER")),
],
targets: [
    .target(
        name: "YOUR_MODULE",
        dependencies: [
            "NeedleFoundation",
        ]),
],

Using CocoaPods

Please follow the standard pod integration process and use NeedleFoundation pod.

Install code generator

Using Carthage

If Carthage is used to integrate the NeedleFoundation framework, then a copy of the code generator executable of the corresponding version is already downloaded in the Carthage folder. It can be found at Carthage/Checkouts/needle/Generator/bin/needle.

Using Homebrew

Regardless of how the NeedleFoundation framework is integrated into your project, the generator can always be installed via Homebrew.

brew install needle

Why use dependency injection?

The linked document uses a somewhat real example to explain what the dependency injection pattern is, and its benefits.

Related projects

If you like Needle, check out other related open source projects from our team:

  • Swift Concurrency: a set of concurrency utility classes used by Uber, inspired by the equivalent java.util.concurrent package classes.
  • Swift Abstract Class: a light-weight library along with an executable that enables compile-time safe abstract class development for Swift projects.
  • Swift Common: common libraries used by this set of Swift open source projects.

License

FOSSA Status

Github

link
Stars: 714

Dependencies

Used By

Total: 1

Releases

Source hashing and reduced generated code - 2020-06-18 21:53:11

  • The generated file now contains a hash of all the files that needle actually looked at. This allows optimizations where we can decide to skip recompiling the generated file if nothing has changed since last time.
  • The generated code is now optimized for the case where a specific needle scope may be attached at various different points in the tree. Until now, this lead to a provider class being generated for every unique path. Now, paths that have similar providers use a base class to shared most of the code.

Generator fix for Swift 5.2 - 2020-04-22 21:43:16

  • Fix generator for Swift 5.2
  • Downgrade orphan scopes from warning to info log

v0.13.0 - 2020-02-28 01:37:52

Make needle binary run faster without accumulating all the extension files' import statements.

Errors now include a complete list of missing dependencies - 2019-09-11 21:40:23

  • Key new feature is that the command-line tool does not exit on the first error. Instead it produces a full report.

Explicit root scope API - 2019-05-14 20:50:49

Fix podspec - 2019-04-24 22:39:16

https://github.com/uber/needle/issues/280

Various strict validation, extension support and renames - 2019-02-27 00:17:48

Please see https://github.com/uber/needle/issues?q=is%3Aissue+is%3Aclosed+label%3A%22Planned+for+v0.9.0%22 for details.

Support passing in individual Swift source files - 2018-12-10 22:12:52

Kill SourceKitService process before retry parsing - 2018-11-20 22:19:42

Support retry parsing and customizing parsing and exporting timeouts - 2018-11-13 21:18:51

Expand tracking task ID to collecting more information - 2018-11-05 22:55:12

First release that includes the Generator - 2018-10-09 21:47:21

This is the first release that includes the binary Generator, which can be invoked to generate Needle DI code.

Fix typo in Foundation protocol - 2018-08-23 21:08:51

Bound PluginizedComponent purely to PluginizedScopeLifecycle - 2018-08-22 23:16:43

PluginExtension use just the component name as key - 2018-07-02 21:35:16

PluginExtension base protocol - 2018-06-27 21:10:47

Merged in pluginized foundation classes - 2018-06-15 23:23:30

Carthage scheme change - 2018-06-01 22:28:20

Cartfile moved to project root - 2018-06-01 22:08:31

iOS deployment target set to 8.0 - 2018-06-01 21:35:38

Updated EmptyDependencyProvider initializer - 2018-05-24 21:58:19

Updated the initializer to take in the source component, so it's uniform with generated code.

Add Dependency protocol and removed Scope protocol - 2018-05-17 23:09:19

Remove module name from component path - 2018-05-08 00:56:41

Initial Foundation release - 2018-05-07 20:39:44

This release only contains Foundation classes.