{"id":17269570,"url":"https://github.com/kanecheshire/blade","last_synced_at":"2025-07-02T17:32:44.024Z","repository":{"id":86949494,"uuid":"307796261","full_name":"KaneCheshire/Blade","owner":"KaneCheshire","description":"A super simple dependency injection library written in Swift. ","archived":false,"fork":false,"pushed_at":"2020-11-10T22:24:44.000Z","size":24,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-14T08:11:28.415Z","etag":null,"topics":["dependency-injection","ios","macos","property-wrapper","resolver","resolver-library","swift","watchos"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KaneCheshire.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"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":"2020-10-27T18:43:13.000Z","updated_at":"2025-02-11T10:15:08.000Z","dependencies_parsed_at":"2023-05-29T23:00:29.620Z","dependency_job_id":null,"html_url":"https://github.com/KaneCheshire/Blade","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/KaneCheshire/Blade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaneCheshire%2FBlade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaneCheshire%2FBlade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaneCheshire%2FBlade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaneCheshire%2FBlade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KaneCheshire","download_url":"https://codeload.github.com/KaneCheshire/Blade/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KaneCheshire%2FBlade/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263184674,"owners_count":23427067,"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":["dependency-injection","ios","macos","property-wrapper","resolver","resolver-library","swift","watchos"],"created_at":"2024-10-15T08:16:47.315Z","updated_at":"2025-07-02T17:32:44.003Z","avatar_url":"https://github.com/KaneCheshire.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blade\n\nA super simple dependency injection library written in Swift. \n\n- [Quick start](#quick-start)\n\t- [Registering types](#1-registering-types)\n\t- [Declaring injected properties](#2-declaring-injected-properties)\n- [Scopes](#scopes)\n- [Qualifiers](#qualifiers)\n- [`@Inject`](#inject)\n- [`@LazyInject`](#lazyinject)\n- [`@WeakInject`](#weakinject)\n\n- [Good to know](#good-to-know)\n\n## Quick start\n\nThere are only two main steps to using Blade before you can start injecting.\n\n### 1: Registering types\n\nBefore Blade knows how to inject a type, you need to register a provider so that it can be injected elsewhere in the project. \n\nA typical place to do this is in the AppDelegate:\n\n```swift\nfunc application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -\u003e Bool {\n\tResolver.register { MyInjectedType() }\n\treturn true\n}\n```\n### 2: Declaring injected properties\n\nOnce you've registered providers, you can then declare where those instances are injected using Blade's property wrappers.\n\n```swift\nclass MyViewController: UIViewController {\n\n\t@Inject\n\tprivate var injectedProperty: MyInjectedType // This is resolved when `MyViewController` is created\n\t\n\t@LazyInject\n\tprivate var lazilyInjectedProperty: MyInjectedType // This is only resolved when first accessing, like when using `lazy var`\n}\n```\n\nYou can also use Blade to inject into initializers, by using `Resolver` directly:\n\n```swift\nclass MyViewModel {\n\n\tinit(injectedArgument: MyInjectedType = Resolver.resolve()) {\n\t\t// Do something with injectedArgument\n\t}\n}\n```\n## Scopes\n\nBy default, Blade will call the provider you register every time you inject or call `Resolver.resolve()`, but you can change this using a `Scope`.\n\nScoped objects are only created whenever first resolved or injected, and persist until every object that holds a reference to the scoped object are destroyed.\n\nAs an example, let's say you had a User object and you want it to be shared across a registration flow. You could inject it using a scope in every controller.\n\nThe first step is to define a new `Scope`, which (similar to a [`Qualifier`](#qualifier)) you do by defining a type that conforms to `Scope`:\n\n```swift\n\nenum RegistrationFlow: Scope {} \n\n```\n\nOnce defined, you register a provider using the scope:\n\n```swift\n\nResolver.register(scopedTo: RegistrationFlow.self) { User() }\n\n```\n\nAnd once registered, you can then start injecting into whatever needs a shared `User` object for the flow:\n\n```swift\n\nclass UsernameRegistrationController: UIViewController {\n\n\t@Inject(RegistrationFlow.self)\n\tprivate var user: User\n}\n\nclass PasswordRegistrationController: UIViewController {\n\n\t@Inject(RegistrationFlow.self)\n\tprivate var user: User // The same instance of User as injected into `UsernameRegistrationController`\n}\n\n```\nSo long as `PasswordRegistrationController` is created before  `UsernameRegistrationController` is destroyed, the `User` instance\nin both controllers will be the same, ready for you to use at the end of the flow.\n\n\u003e *NOTE*: You can only use a Scope with a class types, not value types. So in this case, `User` is a `class`, not a `struct`.\n\nYou can also manually resolve objects for scopes:\n\n```swift\n\nclass RegistrationManager {\n\n\tinit(user: User = Resolver.resolve(scopedTo: RegistrationFlow.self)) {\n\t\t// Do something with user\n\t}\n}\n\n```\nIt's important to understand that objects in a scope are only kept until nothing holds a reference to it. If all objects holding a reference to a scoped\nobject are destroyed, the shared injected/resolved object is also destroyed. The next time an object tries to inject an object with the same scope, a new\ninstance of the scoped object is created.\n\nThe exception to this rule is if you keep a reference elsewhere to the object that you provide when registering a provider for the scope, in that case Blade will\nnot know that a new instance is required so will keep returning the same object until nothing holds a reference to it any more.\n\n## Qualifiers\n\nThere might be times when you want to return different instances of an object depending on the circumstance that it's being used.\n\nBlade currently supports this by you providing a qualifier type when registering a type, and you can use that same qualifier type when resolving, \neither using the `Inject`/`LazyInject` property wrappers, or when using `Resolver` directly.\n\nThe first step is to declare a new type that conforms to `Qualifier`. This could be a `struct`, a `class`, or an `enum`. I recommend using an `enum`, since \nwe're only use the type, not an instance of the type, and `enum`s don't have initializers:\n\n```swift\nenum MyQualifier: Qualifier {}\n```\n\nYou can then use that qualifier when registering a type:\n\n```swift\nResolver.register { MyInjectedType() } // This provider will be used when no qualifier is used when injecting/resolving\nResolver.register(qualifiedBy: MyQualifier.self) { MyInjectedType() } // This provider will only get used when `MyQualifier` is used when injecting/resolving\n```\nOnce you've registered a provider for a qualifier, you can then specify the qualifier to use when injecting:\n\n```swift\nclass MyViewController: UIViewController {\n\n\t@Inject\n\tprivate var injectedProperty: MyInjectedType\n\n\t@Inject(MyQualifier.self)\n\tprivate var injectedQualifiedProperty: MyInjectedType // This will use the instance provided by the registered provider specifically for `MyQualifier`\n}\n```\n\nAnd you can also specify the qualifier if resolving manually:\n\n```swift\nclass MyViewModel {\n\n\tinit(injectedArgument: MyInjectedType = Resolver.resolve(qualifiedBy: MyQualifier.self)) {\n\t\t// Do something with injectedArgument\n\t}\n}\n```\n\n## `@Inject`\n\nBlade comes with some property wrappers to help make injection easy and tidy.\n\nThe most common properry wrapper you would use is probably `@Inject`:\n\n```swift\n\nclass MyViewController: UIViewController {\n\n\t@Inject\n\tvar myInjectedProperty: MyInjectedType\n\n}\n\n```\n\n`@Inject` resolves its type when it's created, so in the example above, `MyInjectedType` is resolved during the creation of `MyViewController`.\n\nThis means that you must have registered a provider before creating `MyViewController`, otherwise Blade won't be able to resolve the type, and \nyour app will crash.\n\n`@Inject` also has some other ways of creating it, so that you can use [Scopes](#scopes) and [Qualifiers](#qualifiers) with it too:\n\n```swift\n\n@Inject(MyScope.self) // Will try to resolve a type scoped to MyScope\n@Inject(MyQualifier.self) // Will try to resolve a type qualified by MyQualifier\n@Inject(MyScope.self, MyQualifier.self) // Will try to resolve a type scoped to MyScope and qualified by MyQualifier\n\n```\n\nYou can also provide a closure to resolve the type if necessary:\n\n```swifft\n@Inject({\n\tMyInjectedType()\n})\n\n@Inject(MyInjectedType())\n```\n\n## `@LazyInject`\n\n`@LazyInject` has the same interface as [`@Inject`](#inject), the difference between the two property wrappers is that `@LazyInject` only resolves\nwhen the injected property is first accessed, rather than when the containing type is created. This is the same as using `lazy var` when declaring a \nproperty.\n\n## `@WeakInject`\n\n`@WeakInject` has the same interface as [`@LazyInject`](#lazyinject) and [`@Inject`](#inject) , except that it doesn't store a strong reference to the\ninjected object. This is the same as using `weak var` when declaring a property, so if nothing else holds a reference to the resolved object it will\nbe deallocated.\n\n\n## Good to know\n\nBlade is very new, and very simple.\n\nCompared to alternatives like [Cleanse](https://github.com/square/Cleanse) for Swift and Dagger for Java, Blade is simple, easy to learn and easy to use, \nbut as a result may not be suitable for large or complex projects.\n\nI'm really keen for you to use it, and let me know what problems you have or whether you think the API needs to change, or if new features are needed.\n\nBlade has no notion of modules or graphs (although it does have [Scopes](#scopes) and [Qualifiers](#qualifiers)). If this impacts you, I'd love to learn more about the use case where\nthis is required over what Blade currently offers, and whether it's something that Blade should include or whether Blade should commit to being simple and\nonly used in simple projects.\n\n## Installation\n\nBlade is only available via Swift Package Manager. From Xcode 11 and newer you can specify Blade as a remote dependency and Xcode will automatically\nhandle resolving and including the dependency for you. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanecheshire%2Fblade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkanecheshire%2Fblade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanecheshire%2Fblade/lists"}