You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
12 KiB

2 years ago
  1. <p align="center">
  2. <img src="https://avatars0.githubusercontent.com/u/13637225?v=3&s=600" width="33%">
  3. </p>
  4. Swinject
  5. ========
  6. [![Travis CI](https://travis-ci.org/Swinject/Swinject.svg?branch=master)](https://travis-ci.org/Swinject/Swinject)
  7. [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
  8. [![CocoaPods Version](https://img.shields.io/cocoapods/v/Swinject.svg?style=flat)](http://cocoapods.org/pods/Swinject)
  9. [![License](https://img.shields.io/cocoapods/l/Swinject.svg?style=flat)](http://cocoapods.org/pods/Swinject)
  10. [![Platforms](https://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-lightgrey.svg)](http://cocoapods.org/pods/Swinject)
  11. [![Swift Version](https://img.shields.io/badge/Swift-2.2--3.1.x-F16D39.svg?style=flat)](https://developer.apple.com/swift)
  12. [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
  13. Swinject is a lightweight [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) framework for Swift.
  14. Dependency injection (DI) is a software design pattern that implements Inversion of Control (IoC) for resolving dependencies. In the pattern, Swinject helps your app split into loosely-coupled components, which can be developed, tested and maintained more easily. Swinject is powered by the Swift generic type system and first class functions to define dependencies of your app simply and fluently.
  15. ## Features
  16. - [x] [Pure Swift Type Support](./Documentation/README.md#user-content-pure-swift-type-support)
  17. - [x] [Injection with Arguments](./Documentation/DIContainer.md#registration-with-arguments-to-di-container)
  18. - [x] [Initializer/Property/Method Injections](./Documentation/InjectionPatterns.md)
  19. - [x] [Initialization Callback](./Documentation/InjectionPatterns.md#user-content-initialization-callback)
  20. - [x] [Circular Dependency Injection](./Documentation/CircularDependencies.md)
  21. - [x] [Object Scopes as None (Transient), Graph, Container (Singleton) and Hierarchy](./Documentation/ObjectScopes.md)
  22. - [x] Support of both Reference and [Value Types](./Documentation/Misc.md#value-types)
  23. - [x] [Self-registration (Self-binding)](./Documentation/Misc.md#self-registration-self-binding)
  24. - [x] [Container Hierarchy](./Documentation/ContainerHierarchy.md)
  25. - [x] [Thread Safety](./Documentation/ThreadSafety.md)
  26. - [x] [Modular Components](./Documentation/Assembler.md)
  27. ## Extensions
  28. - **[SwinjectPropertyLoader](https://github.com/Swinject/SwinjectPropertyLoader)**: Loading property values from resources.
  29. - **[SwinjectStoryboard](https://github.com/Swinject/SwinjectStoryboard)**: Automatic dependency injection via Storyboard.
  30. - **[Swinject-CodeGen](https://github.com/Swinject/Swinject-CodeGen)**: Type-safe code generation of `Container` from a CSV/YAML file defining dependencies.
  31. - **[SwinjectAutoregistration](https://github.com/Swinject/SwinjectAutoregistration)**: Automatic registration of services by leveraging the Swift Generics.
  32. ## Requirements
  33. - iOS 8.0+ / Mac OS X 10.10+ / watchOS 2.0+ / tvOS 9.0+
  34. - Swift 2.2 or 2.3
  35. - Xcode 7.0+
  36. - Swift 3
  37. - Xcode 8.0+
  38. - Swift 3.2, 4.x
  39. - Xcode 9.0+
  40. - Carthage 0.18+ (if you use)
  41. - CocoaPods 1.1.1+ (if you use)
  42. ## Installation
  43. Swinject is available through [Carthage](https://github.com/Carthage/Carthage) or [CocoaPods](https://cocoapods.org).
  44. ### Carthage
  45. To install Swinject with Carthage, add the following line to your `Cartfile`.
  46. #### Swift 2.2 or 2.3
  47. ```
  48. github "Swinject/Swinject" ~> 1.1.4
  49. ```
  50. #### Swift 3.x or 4.x
  51. ```
  52. github "Swinject/Swinject"
  53. # Uncomment if you use SwinjectStoryboard
  54. # github "Swinject/SwinjectStoryboard"
  55. ```
  56. Then run `carthage update --no-use-binaries` command or just `carthage update`. For details of the installation and usage of Carthage, visit [its project page](https://github.com/Carthage/Carthage).
  57. ### CocoaPods
  58. To install Swinject with CocoaPods, add the following lines to your `Podfile`.
  59. #### Swift 2.2 or 2.3
  60. ```ruby
  61. source 'https://github.com/CocoaPods/Specs.git'
  62. platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
  63. use_frameworks!
  64. pod 'Swinject', '~> 1.1.4'
  65. ```
  66. #### Swift 3.x
  67. ```ruby
  68. source 'https://github.com/CocoaPods/Specs.git'
  69. platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
  70. use_frameworks!
  71. pod 'Swinject'
  72. # Uncomment if you use SwinjectStoryboard
  73. # pod 'SwinjectStoryboard'
  74. ```
  75. Then run `pod install` command. For details of the installation and usage of CocoaPods, visit [its official website](https://cocoapods.org).
  76. ## Documentation
  77. - [Technical documents](./Documentation) including patterns of dependency injection and examples.
  78. - [API reference](http://cocoadocs.org/docsets/Swinject/)
  79. ## Basic Usage
  80. First, register a service and component pair to a `Container`, where the component is created by the registered closure as a factory. In this example, `Cat` and `PetOwner` are component classes implementing `Animal` and `Person` service protocols, respectively.
  81. ```swift
  82. let container = Container()
  83. container.register(Animal.self) { _ in Cat(name: "Mimi") }
  84. container.register(Person.self) { r in
  85. PetOwner(pet: r.resolve(Animal.self)!)
  86. }
  87. ```
  88. Then get an instance of a service from the container. The person is resolved to a pet owner, and playing with the cat named Mimi!
  89. ```swift
  90. let person = container.resolve(Person.self)!
  91. person.play() // prints "I'm playing with Mimi."
  92. ```
  93. Where definitions of the protocols and classes are
  94. ```swift
  95. protocol Animal {
  96. var name: String? { get }
  97. }
  98. class Cat: Animal {
  99. let name: String?
  100. init(name: String?) {
  101. self.name = name
  102. }
  103. }
  104. ```
  105. and
  106. ```swift
  107. protocol Person {
  108. func play()
  109. }
  110. class PetOwner: Person {
  111. let pet: Animal
  112. init(pet: Animal) {
  113. self.pet = pet
  114. }
  115. func play() {
  116. let name = pet.name ?? "someone"
  117. print("I'm playing with \(name).")
  118. }
  119. }
  120. ```
  121. Notice that the `pet` of `PetOwner` is automatically set as the instance of `Cat` when `Person` is resolved to the instance of `PetOwner`. If a container already set up is given, you do not have to care what are the actual types of the services and how they are created with their dependency.
  122. ## Where to Register Services
  123. Services must be registered to a container before they are used. The typical registration approach will differ depending upon whether you are using `SwinjectStoryboard` or not.
  124. The following view controller class is used in addition to the protocols and classes above in the examples below.
  125. ```swift
  126. class PersonViewController: UIViewController {
  127. var person: Person?
  128. }
  129. ```
  130. ### With SwinjectStoryboard
  131. Import SwinjectStoryboard at the top of your swift source file if you use Swinject v2 in Swift 3.
  132. ```swift
  133. // Only Swinject v2 in Swift 3.
  134. import SwinjectStoryboard
  135. ```
  136. Services should be registered in an extension of `SwinjectStoryboard` if you use `SwinjectStoryboard`. Refer to [the project page of SwinjectStoryboard](https://github.com/Swinject/SwinjectStoryboard) for further details.
  137. ```swift
  138. extension SwinjectStoryboard {
  139. @objc class func setup() {
  140. defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
  141. defaultContainer.register(Person.self) { r in
  142. PetOwner(pet: r.resolve(Animal.self)!)
  143. }
  144. defaultContainer.register(PersonViewController.self) { r in
  145. let controller = PersonViewController()
  146. controller.person = r.resolve(Person.self)
  147. return controller
  148. }
  149. }
  150. }
  151. ```
  152. ### Without SwinjectStoryboard
  153. If you do not use `SwinjectStoryboard` to instantiate view controllers, services should be registered to a container in your application's `AppDelegate`. Registering before exiting `application:didFinishLaunchingWithOptions:` will ensure that the services are setup appropriately before they are used.
  154. ```swift
  155. class AppDelegate: UIResponder, UIApplicationDelegate {
  156. var window: UIWindow?
  157. let container: Container = {
  158. let container = Container()
  159. container.register(Animal.self) { _ in Cat(name: "Mimi") }
  160. container.register(Person.self) { r in
  161. PetOwner(pet: r.resolve(Animal.self)!)
  162. }
  163. container.register(PersonViewController.self) { r in
  164. let controller = PersonViewController()
  165. controller.person = r.resolve(Person.self)
  166. return controller
  167. }
  168. return container
  169. }()
  170. func application(
  171. _ application: UIApplication,
  172. didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
  173. // Instantiate a window.
  174. let window = UIWindow(frame: UIScreen.main.bounds)
  175. window.makeKeyAndVisible()
  176. self.window = window
  177. // Instantiate the root view controller with dependencies injected by the container.
  178. window.rootViewController = container.resolve(PersonViewController.self)
  179. return true
  180. }
  181. }
  182. ```
  183. Notice that the example uses a convenience initializer taking a closure to register services to the new instance of `Container`.
  184. ## Play in Playground!
  185. The project contains `Sample-iOS.playground` to demonstrate the features of Swinject. Download or clone the project, run the playground, modify it, and play with it to learn Swinject.
  186. To run the playground in the project, first build the project, then select `Editor > Execute Playground` menu in Xcode.
  187. ## Example Apps
  188. - [SwinjectSimpleExample](https://github.com/Swinject/SwinjectSimpleExample) demonstrates dependency injection and Swinject in a simple weather app that lists current weather information at some locations.
  189. - [SwinjectMVVMExample](https://github.com/Swinject/SwinjectMVVMExample) demonstrates dependency injection with Swift and reactive programming with [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) in MVVM architecture.
  190. ## Blog Posts
  191. The following blog posts introduce Swinject and the concept of dependency injection.
  192. - [Dependency Injection Framework for Swift - Introduction to Swinject](https://yoichitgy.github.io/post/dependency-injection-framework-for-swift-introduction-to-swinject/)
  193. - [Dependency Injection Framework for Swift - Simple Weather App Example with Swinject Part 1/2](https://yoichitgy.github.io/post/dependency-injection-framework-for-swift-simple-weather-app-example-with-swinject-part-1/)
  194. - [Dependency Injection Framework for Swift - Simple Weather App Example with Swinject Part 2/2](https://yoichitgy.github.io/post/dependency-injection-framework-for-swift-simple-weather-app-example-with-swinject-part-2/)
  195. ## Contribution Guide
  196. A guide to [submit issues](https://github.com/Swinject/Swinject/issues), to ask general questions, or to [open pull requests](https://github.com/Swinject/Swinject/pulls) is [here](CONTRIBUTING.md).
  197. ## Question?
  198. - [Slack](https://join.slack.com/t/swinject/shared_invite/enQtNjk0NjE0NjMzOTIyLTI5NWJiNDU5NGI1MTUwZDI3MDU2ZTM2YTMwMWRhMjI0ZmFlODk4MDI5OWUwNzY1YjlhOTRjYWM2NjZmOTVhNTU) feel free to discuss anything Swinject related.
  199. - [Stack Overflow](https://stackoverflow.com/questions/tagged/swinject) we are trying to monitor questions tagged `swinject`
  200. ## Credits
  201. The DI container features of Swinject are inspired by:
  202. - [Ninject](http://ninject.org) - [Enkari, Ltd](https://github.com/enkari) and [the Ninject project contributors](https://github.com/ninject/Ninject/graphs/contributors).
  203. - [Autofac](http://autofac.org) - [Autofac Project](https://github.com/autofac/Autofac).
  204. and highly inspired by:
  205. - [Funq](http://funq.codeplex.com) - [Daniel Cazzulino](http://www.codeplex.com/site/users/view/dcazzulino) and [the project team](http://funq.codeplex.com/team/view).
  206. ## License
  207. MIT license. See the [LICENSE file](LICENSE.txt) for details.