{"id":20650933,"url":"https://github.com/coolsamson7/inject","last_synced_at":"2025-09-14T16:11:03.171Z","repository":{"id":56932438,"uuid":"63603818","full_name":"coolsamson7/inject","owner":"coolsamson7","description":"Dependency Injection Container for Swift","archived":false,"fork":false,"pushed_at":"2017-04-12T12:26:12.000Z","size":337,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-13T11:30:10.875Z","etag":null,"topics":["injection","injection-container","logger","swift","xml-parser"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coolsamson7.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-18T13:08:28.000Z","updated_at":"2017-02-24T08:02:01.000Z","dependencies_parsed_at":"2022-08-21T00:40:26.659Z","dependency_job_id":null,"html_url":"https://github.com/coolsamson7/inject","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/coolsamson7/inject","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Finject","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Finject/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Finject/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Finject/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coolsamson7","download_url":"https://codeload.github.com/coolsamson7/inject/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Finject/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275129247,"owners_count":25410447,"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","status":"online","status_checked_at":"2025-09-14T02:00:10.474Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["injection","injection-container","logger","swift","xml-parser"],"created_at":"2024-11-16T17:24:36.146Z","updated_at":"2025-09-14T16:11:03.144Z","avatar_url":"https://github.com/coolsamson7.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# inject\n\n[![Swift Version](https://img.shields.io/badge/Swift-3.1-F16D39.svg?style=flat)](https://developer.apple.com/swift)\n[![Build Status](https://travis-ci.org/coolsamson7/inject.svg?style=flat)](https://travis-ci.org/coolsamson7/inject)\n[![CocoaPods](https://img.shields.io/cocoapods/v/inject.svg)](https://github.com/coolsamson7/inject)\n[![Platform](https://img.shields.io/cocoapods/p/inject.svg?style=flat)](http://cocoapods.org/pods/inject)\n[![License][mit-badge]][mit-url]\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://cloud.githubusercontent.com/assets/19403960/17474460/43a71bd6-5d56-11e6-9bcb-6d2aaa9ac466.png\" width=\"40%\"\u003e\n\u003c/p\u003e\n\n`Inject` is a dependency injection container for Swift that picks up the basic `Spring` ideas - as far as they are possible to be implemented - and additionally utilizes the Swift language features - e.g. closures - in order to provide a simple and intuitive api.\n\nIn addition to the core a number of other concepts are implemented\n* basic reflection and type introspection framework \n* configuration framework\n* logging \u0026  tracing framework\n* concurrency classes\n* xml parser\n* type conversion facilities\n\nBut let's come back to the dependency container again :-)\n\n# What's a dependency injection container anyway?\n\nThe basic idea is to have one central object that knows about all kind of different object types as well as object dependencies and whose task is to instantiate and assemble them appropriately by populating fields ( with property setters, methods or appropriate constructor calls ). Classes do not have to know anything about the current constallation - e.g. specific  protocol implementation, or specific configuration values - as this know how is solely in the responsiblity of the container and injected into the classes.\n\nIf you think about unit testing, where service implementations need to be exchanged by some kind of local variants ( e.g. mocks ) you get a feeling for the benefits.\n\nThe other big benefit is that the lifecycle of objects is also managed by a central instance. This on the one hand avoids singleton patterns all over your code - which simply is a mess - and on the other hand allows for other features such as session scoped objects, or the possibility to shutdown the complete container - releasing ressources - with on call.\n\n# Features\n\nHere is a summary of the supported features\n* specification of beans via a fluent interface or xml\n* full dependency management including cycle detection \n* all defintions are checked for typesafeness\n* integrated management of configuration values\n* injections resembling the spring `@Inject` autowiring mechanism\n* support for different scopes including `singleton`  and `protoype` as builtin flavors\n* support for lazy initialized beans\n* support for bean templates\n* lifecycle methods ( e.g. `postConstruct` )\n* `BeanPostProcessor`'s\n* `FactoryBean`'s\n* support for hierarchical containers, that inherit beans ( and post processors )\n* support for placeholder resolution ( e.g. `${property=\u003cdefault\u003e}`) in xml \n* support for custom namespace handlers in xml\n* automatic type conversions and number coercions in xml\n\n# Documentation\n\nFor detailed information please visit\n\n* The [Wiki](https://github.com/coolsamson7/inject/wiki) and\n* the generated [API Docs](http://cocoadocs.org/docsets/inject/1.0.2/)\n* or simply play around with the included playground\n\n# Examples\n\nLet's look at some simple examples.\n\n```Swift\nlet environment = try! Environment(name: \"my first environment\")\n\ntry! environment\n   // a bar created by the default constructor\n   \n   .define(environment.bean(Bar.self, factory: Bar.init))\n   \n   // a foo that depends on bar\n   \n   .define(environment.bean(Foo.self, factory: {\n            return Foo(bar: try! environment.getBean(Bar.self))\n        }).requires(class: Bar.self))\n        \n   // get goin'\n   \n   .startup()\n```\n\nOne the environment is configured, beans can simply be retrieved via the `getBean()` function.\n\n```Swift\nlet foo = try environment.getBean(Foo.self)\n```\nBehind the scenes all bean definitions will be validated - e.g. looking for cyclic dependencies or non resolvable dependencies - and all singleton beans will be eagerly constructed.\n\nOther injections - here property injections - can be expressed via the fluent interface\n\n```Swift\nenvironment.define(environment.bean(Foo.self, id: \"foo-1\")\n   .property(\"name\", value: \"foo\")\n   .property(\"number\", value: 7))\n```\n\n**Injections**\n\nA similar concept as the Java `@Inject` annotations is available that let's you define injections on a class basis.\n\n```Swift\npublic class AbstractConfigurationSource : NSObject, Bean, BeanDescriptorInitializer, ... {\n    // MARK: instance data\n    \n    ...\n    var configurationManager : ConfigurationManager? = nil // injected\n    \n    ...\n    \n    // MARK: implement BeanDescriptorInitializer\n    \n    public func initializeBeanDescriptor(beanDescriptor : BeanDescriptor) {\n        beanDescriptor[\"configurationManager\"].inject(InjectBean())\n    }\n    \n    // MARK: implement Bean\n    \n    // we know, that all injections have been executed....\n    public func postConstruct() throws -\u003e Void {\n        try configurationManager!.addSource(self)\n    }\n```\n\nThe protocol `BeanDescriptorInitializer` can be implemented for thus purpose in order to add inejctions to properties. Valid values are:\n* `InjectBean` an injection for a specific object type\n* `InjectConfigurationValue` an injection of a configuration value\n\n**Scopes**\n\nScopes determine when and how often a bean instance is created. \n* The default is \"singleton\", which will create an instance once and will cache the value.\n* \"prototype\" will recreate a  new instance whenever a bean is requested.\n\n**Example**: \n```Swift\nenvironment.define(environment.bean(Foo.self)\n   .scope(\"prototype\")\n   .property(\"name\", value: \"foo\")\n   .property(\"number\", value: 7))\n```\n\nOther scopes can be simply added (e.g. session scope ) by defining the implementing class in the current environment.\n\n**Lazy Beans**\n\nBeans that are marked as lazy will be constructed after the first request.\n\n**Factory Beans**\n\nFactory beans are beans that implement a specific protocol and create other beans in turn.\n\n```Swift\nenvironment\n   .define(environment.bean(FooFactory.self)\n      .property(\"someProperty\", value: \"...\") // configure the factory....\n      .target(Foo.self) // i will create foo's\n    )\n    \nlet foo = environment.getBean(Foo.self) // is created by the factory!\n```\n\n**Abstract Beans**\n\nIt is possible to define a bean skeletton - possibly hiding ugly technical parameters - and let the programmer finsh configuration by adding the missing parts:\n\n```Swift\nenvironment\n   // a template\n\n   .define(environment.bean(Foo.self, id: \"foo-template\", abstract: true)\n      .property(\"url\", value: \"...\")\n      .property(\"port\", value: 8080))\n   \n   // the concrete bean\n   \n   .define(environment.bean(Foo.self, parent: \"foo-template\")\n      .property(\"missing\", value: \"foo\") // add missing properties\n   )\n```\nUsually templates are part of a parent environment to separate technical aspects.\n\n**Bean Post Processor**\n\nBean Post Processors are classes that implement a specific protocol and are called by the container in order to modify the to be constructed instance.\n\n**Lifecycle Callbacks**\n\nDifferent protocols can be implemenetd by classes which will be called by the container when an instance is created.\nThe most important is a `postConstruct` that is called after the instance has been created and all psot processors have been executed. \n\n**Configuration Values**\n\nEvery container defines a central registry that maintains configuration values - from different sources - that can be retrieved with an uniform api.\n\n```Swift\nlet environment = ...\nenvironment.addConfigurationSource(ProcessInfoConfigurationSource()) // process info\nenvironment.addConfigurationSource(PlistConfigurationSource(name: \"Info\")) // will read Info.plist in the current bundle\n\n// retrieve some values\n\nenvironment.getConfigurationValue(Int.self, key: \"SIMULATOR_MAINSCREEN_HEIGHT\", defaultValue: 100) // implicit conversion!\n```\n\n**XML Configuration**\n\nAnd for all xml lovers ( :-) ), an xml parser for the original - at least a subset - spring schema.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cbeans\n        xmlns:configuration=\"http://www.springframework.org/schema/configuration\"\n        xmlns=\"http://www.springframework.org/schema/beans\"\n        xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd\n                        http://www.springframework.org/schema/configuration http://www.springframework.org/schema/util/spring-util.xsd\"\u003e\n    \n    \u003c!-- configuration values are collected from different sources and can be referenced in xml and the api --\u003e\n    \u003c!-- in addition to static values dynamic sources are supported that will trigger listeners or simply change injected values on the fly--\u003e\n    \n    \u003c!-- here are some examples for sources --\u003e\n    \n    \u003c!-- builtin namespace \u0026 corresponding handler to set configuration values --\u003e\n\n    \u003cconfiguration:configuration namespace=\"com.foo\"\u003e\n        \u003cconfiguration:define key=\"bar\" type=\"Int\" value=\"1\"/\u003e\n    \u003c/configuration:configuration\u003e\n    \n    \u003c!-- other supported sources are --\u003e\n    \n    \u003c!-- the current process info values, e.g. \"PATH\" --\u003e\n    \n    \u003cbean class=\"Inject.ProcessInfoConfigurationSource\"/\u003e\n    \n    \u003c!-- a plist --\u003e\n\n    \u003cbean class=\"Inject.PlistConfigurationSource\"\u003e\n        \u003cproperty name=\"name\" value=\"Info\"/\u003e\n    \u003c/bean\u003e\n    \n    \u003c!-- a post processor will be called by the container after construction giving it the chance --\u003e\n    \u003c!-- to modify it or completely exchange it with another object ( proxy... ) --\u003e\n    \n    \u003c!-- here we simple print every bean on stdout...:-) --\u003e\n\n    \u003cbean class=\"SamplePostProcessor\"/\u003e\n\n    \u003c!-- create some foo's --\u003e\n\n    \u003c!-- depends-on will switch the instantiation order --\u003e\n\n    \u003cbean id=\"foo-1\" class=\"Foo\" depends-on=\"foo-2\"\u003e\n        \u003cproperty name=\"id\" value=\"foo-1\"/\u003e\n        \u003c!-- references an unknown configuration key, which will set the default value instead... --\u003e\n        \u003cproperty name=\"number\" value=\"${dunno=1}\"/\u003e\n    \u003c/bean\u003e\n\n    \u003cbean id=\"foo-2\" class=\"Foo\"\u003e\n        \u003cproperty name=\"id\" value=\"foo-2\"/\u003e\n        \u003c!-- same thing recursively --\u003e\n        \u003cproperty name=\"number\" value=\"${dunno=${wtf=1}}\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- scope prototype means that whenever the bean is requestd a new instance will be created ( default scope is singleton ) --\u003e\n    \u003c!-- other scopes yould be easily added, e.g. a session scope... --\u003e\n\n    \u003cbean id=\"foo-prototype\" class=\"Foo\" scope=\"prototype\"\u003e\n        \u003cproperty name=\"id\" value=\"foo-prototype\"/\u003e\n        \u003c!-- this should work... the : separates the namespace from the key! --\u003e\n        \u003cproperty name=\"number\" value=\"${com.foo:bar}\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- bar will be injected by all foo's. Obviously the bar needs to be constructed first --\u003e\n\n    \u003cbean id=\"bar-parent\" class=\"Bar\" abstract=\"true\"\u003e\n        \u003cproperty name=\"magic\" value=\"4711\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- will inherit the magic number --\u003e\n    \u003c!-- lazy means that it will be constructed when requested for the first time --\u003e\n\n    \u003cbean id=\"bar\" class=\"Bar\" parent=\"bar-parent\" lazy=\"true\"\u003e\n        \u003cproperty name=\"id\" value=\"bar\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- both foo's will inject the bar instance --\u003e\n\n    \u003c!-- baz factory will create Baz instances... --\u003e\n\n    \u003cbean class=\"BazFactory\" target=\"Baz\"\u003e\n        \u003cproperty name=\"name\" value=\"factory\"/\u003e\n        \u003c!-- will be set as the baz id... --\u003e\n        \u003cproperty name=\"id\" value=\"id\"/\u003e\n    \u003c/bean\u003e\n\n    \u003c!-- bazongs --\u003e\n\n    \u003cbean id=\"bazong-1\" class=\"Bazong\"\u003e\n        \u003cproperty name=\"id\" value=\"id\"/\u003e\n        \u003c!-- by reference --\u003e\n        \u003cproperty name=\"foo\" ref=\"foo-1\"/\u003e\n    \u003c/bean\u003e\n\n    \u003cbean id=\"bazong-2\" class=\"Bazong\"\u003e\n        \u003cproperty name=\"id\" value=\"id\"/\u003e\n        \u003c!-- in-place --\u003e\n        \u003cproperty name=\"foo\"\u003e\n            \u003cbean class=\"Foo\"\u003e\n                \u003cproperty name=\"id\" value=\"foo-3\"/\u003e\n                \u003cproperty name=\"number\" value=\"1\"/\u003e\n            \u003c/bean\u003e\n        \u003c/property\u003e\n    \u003c/bean\u003e\n\u003c/beans\u003e\n```\n\n```Swift\nvar environment = Environment(name: \"environment\")\nvar data : NSData = ...\nenvironment\n   .loadXML(data)\n   .startup()  \n```\n\n# Logging\n\nIn addition to the injection container, a logging framework has been implemented - and integrated - as well.  \n\nOnce the singleton is configured\n\n```swift\n// a composition of the different possible log entry constituents\n\nlet formatter = LogFormatter.timestamp(\"dd/M/yyyy, H:mm:s\") + \" [\" + LogFormatter.logger() + \"] \" + LogFormatter.level() + \" - \" + LogFormatter.message()\nlet consoleLogger = ConsoleLog(name: \"console\", formatter: formatter, synchronize: false)\n\nLogManager() \n           .registerLogger(\"\", level : .OFF, logs: [QueuedLog(name: \"console\", delegate: consoleLogger)]) // root logger\n           .registerLogger(\"Inject\", level : .WARN) // will inherit all log destinations\n           .registerLogger(\"Inject.Environment\", level : .ALL)\n```\n\nthe usual methods are provided\n\n```swift\n// this is usually a static var in a class!\nvar logger = LogManager.getLogger(forClass: MyClass.self) // will lookup with the fully qualified name\n\nlogger.warn(\"ouch!\") // this is a autoclosure!\n\nlogger.fatal(SomeError(), message: \"ouch\")\n```\nThe `error` and `fatal` functions are called with an `ErrorType` argument. Both functions will emit an message containing the original message, the error representation and the current stacktrace.\n\nProvided log destinations are\n* console\n* file\n* rolling file log (logs get copied every day) \n* nslog\n* queued log destination\n\nThe queueded log destination uses a dispatch queue. As a default a serial queue will be created whose purpose simply is to serialize the entries. In this case ´synchronize: false´ prevents that the console operations are synchronized with a Mutex\n\n## Requirements\n\n- iOS 8.0+\n- OSX 10.9\n- WatchOS 2.0\n- TvOS 9.0\n- Xcode 7.0+\n\n# Installation\n\n## Cocoapods\n\nTo install with CocoaPods, add `pod 'inject', '~\u003e 1.0.2'`  to your `Podfile`, e.g.\n\n```ruby\ntarget 'MyApp' do\n  pod 'inject', '~\u003e 1.0.2'\nend\n```\n\nThen run `pod install` command. For details of the installation and usage of CocoaPods, visit [its official website](https://cocoapods.org).\n\n# Limitations\n\nDepending on the specific bean definition, it may be required that the corresponding classes derive from `NSObject`.\nThis limitation is due to the - missing - `Swift` support for relection. As soon as the language evolves i would change that. \n\n# Roadmap\n* support more package managers\n* wait for replies :-)\n\n## License\n\nThis project is released under the MIT license. See [LICENSE](LICENSE) for details.\n\n[swift-badge]: https://img.shields.io/badge/Swift-3.0-orange.svg?style=flat\n[swift-url]: https://swift.org\n[mit-badge]: https://img.shields.io/badge/License-MIT-blue.svg?style=flat\n[mit-url]: https://tldrlegal.com/license/mit-license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolsamson7%2Finject","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoolsamson7%2Finject","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolsamson7%2Finject/lists"}