├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── Shank │ └── Shank.swift └── Tests └── ShankTests └── ShankTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Zamzam Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Shank", 8 | platforms: [ 9 | .macOS(.v10_12), 10 | .iOS(.v10), 11 | .tvOS(.v10), 12 | .watchOS(.v3) 13 | ], 14 | products: [ 15 | .library( 16 | name: "Shank", 17 | targets: ["Shank"] 18 | ) 19 | ], 20 | targets: [ 21 | .target( 22 | name: "Shank" 23 | ), 24 | .testTarget( 25 | name: "ShankTests", 26 | dependencies: ["Shank"] 27 | ) 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shank 2 | 3 | A Swift micro-library that provides lightweight dependency injection. 4 | 5 | Read more here: https://basememara.com/swift-dependency-injection-via-property-wrapper/ 6 | 7 | Inject dependencies via property wrappers: 8 | ```swift 9 | class ViewController: UIViewController { 10 | 11 | @Inject private var widgetModule: WidgetModuleType 12 | @Inject private var sampleModule: SampleModuleType 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | widgetModule.test() 18 | sampleModule.test() 19 | } 20 | } 21 | ``` 22 | Register modules early in your app: 23 | ```swift 24 | class AppDelegate: UIResponder, UIApplicationDelegate { 25 | 26 | private let dependencies = Dependencies { 27 | Module { WidgetModule() as WidgetModuleType } 28 | Module { SampleModule() as SampleModuleType } 29 | } 30 | 31 | override init() { 32 | super.init() 33 | dependencies.build() 34 | } 35 | } 36 | ``` 37 | If you forget to `build` the dependency container, it will result in a run-time exception. 38 | Since there is no type-safety to guard against this, it is recommended to 39 | limit the dependency container to hold "modules" only: 40 | ```swift 41 | struct WidgetModule: WidgetModuleType { 42 | 43 | func component() -> WidgetWorkerType { 44 | WidgetWorker( 45 | store: component(), 46 | remote: component() 47 | ) 48 | } 49 | 50 | func component() -> WidgetRemote { 51 | WidgetNetworkRemote(httpService: component()) 52 | } 53 | 54 | func component() -> WidgetStore { 55 | WidgetRealmStore() 56 | } 57 | 58 | func component() -> HTTPServiceType { 59 | HTTPService() 60 | } 61 | 62 | func test() -> String { 63 | "WidgetModule.test()" 64 | } 65 | } 66 | 67 | struct SampleModule: SampleModuleType { 68 | 69 | func component() -> SomeObjectType { 70 | SomeObject() 71 | } 72 | 73 | func component() -> AnotherObjectType { 74 | AnotherObject(someObject: component()) 75 | } 76 | 77 | func component() -> ViewModelObjectType { 78 | SomeViewModel( 79 | someObject: component(), 80 | anotherObject: component() 81 | ) 82 | } 83 | 84 | func component() -> ViewControllerObjectType { 85 | SomeViewController() 86 | } 87 | 88 | func test() -> String { 89 | "SampleModule.test()" 90 | } 91 | } 92 | 93 | // MARK: API 94 | 95 | protocol WidgetModuleType { 96 | func component() -> WidgetWorkerType 97 | func component() -> WidgetRemote 98 | func component() -> WidgetStore 99 | func component() -> HTTPServiceType 100 | func test() -> String 101 | } 102 | 103 | protocol SampleModuleType { 104 | func component() -> SomeObjectType 105 | func component() -> AnotherObjectType 106 | func component() -> ViewModelObjectType 107 | func component() -> ViewControllerObjectType 108 | func test() -> String 109 | } 110 | ``` 111 | Then resolve individual components lazily: 112 | ```swift 113 | class ViewController: UIViewController { 114 | 115 | @Inject private var widgetModule: WidgetModuleType 116 | @Inject private var sampleModule: SampleModuleType 117 | 118 | private lazy var widgetWorker: WidgetWorkerType = widgetModule.component() 119 | private lazy var someObject: SomeObjectType = sampleModule.component() 120 | private lazy var anotherObject: AnotherObjectType = sampleModule.component() 121 | private lazy var viewModelObject: ViewModelObjectType = sampleModule.component() 122 | private lazy var viewControllerObject: ViewControllerObjectType = sampleModule.component() 123 | 124 | override func viewDidLoad() { 125 | super.viewDidLoad() 126 | 127 | widgetModule.test() //"WidgetModule.test()" 128 | sampleModule.test() //"SampleModule.test()" 129 | widgetWorker.fetch(id: 3) //"|MediaRealmStore.3||MediaNetworkRemote.3|" 130 | someObject.testAbc() //"SomeObject.testAbc" 131 | anotherObject.testXyz() //"AnotherObject.testXyz|SomeObject.testAbc" 132 | viewModelObject.testLmn() //"SomeViewModel.testLmn|SomeObject.testAbc" 133 | viewModelObject.testLmnNested() //"SomeViewModel.testLmnNested|AnotherObject.testXyz|SomeObject.testAbc" 134 | viewControllerObject.testRst() //"SomeViewController.testRst|SomeObject.testAbc" 135 | viewControllerObject.testRstNested() //"SomeViewController.testRstNested|AnotherObject.testXyz|SomeObject.testAbc" 136 | } 137 | } 138 | 139 | // MARK: - Subtypes 140 | 141 | extension DependencyTests { 142 | 143 | struct WidgetModule: WidgetModuleType { 144 | 145 | func component() -> WidgetWorkerType { 146 | WidgetWorker( 147 | store: component(), 148 | remote: component() 149 | ) 150 | } 151 | 152 | func component() -> WidgetRemote { 153 | WidgetNetworkRemote(httpService: component()) 154 | } 155 | 156 | func component() -> WidgetStore { 157 | WidgetRealmStore() 158 | } 159 | 160 | func component() -> HTTPServiceType { 161 | HTTPService() 162 | } 163 | 164 | func test() -> String { 165 | "WidgetModule.test()" 166 | } 167 | } 168 | 169 | struct SampleModule: SampleModuleType { 170 | 171 | func component() -> SomeObjectType { 172 | SomeObject() 173 | } 174 | 175 | func component() -> AnotherObjectType { 176 | AnotherObject(someObject: component()) 177 | } 178 | 179 | func component() -> ViewModelObjectType { 180 | SomeViewModel( 181 | someObject: component(), 182 | anotherObject: component() 183 | ) 184 | } 185 | 186 | func component() -> ViewControllerObjectType { 187 | SomeViewController() 188 | } 189 | 190 | func test() -> String { 191 | "SampleModule.test()" 192 | } 193 | } 194 | 195 | struct SomeObject: SomeObjectType { 196 | func testAbc() -> String { 197 | "SomeObject.testAbc" 198 | } 199 | } 200 | 201 | struct AnotherObject: AnotherObjectType { 202 | private let someObject: SomeObjectType 203 | 204 | init(someObject: SomeObjectType) { 205 | self.someObject = someObject 206 | } 207 | 208 | func testXyz() -> String { 209 | "AnotherObject.testXyz|" + someObject.testAbc() 210 | } 211 | } 212 | 213 | struct SomeViewModel: ViewModelObjectType { 214 | private let someObject: SomeObjectType 215 | private let anotherObject: AnotherObjectType 216 | 217 | init(someObject: SomeObjectType, anotherObject: AnotherObjectType) { 218 | self.someObject = someObject 219 | self.anotherObject = anotherObject 220 | } 221 | 222 | func testLmn() -> String { 223 | "SomeViewModel.testLmn|" + someObject.testAbc() 224 | } 225 | 226 | func testLmnNested() -> String { 227 | "SomeViewModel.testLmnNested|" + anotherObject.testXyz() 228 | } 229 | } 230 | 231 | class SomeViewController: ViewControllerObjectType { 232 | @Inject private var module: SampleModuleType 233 | 234 | private lazy var someObject: SomeObjectType = module.component() 235 | private lazy var anotherObject: AnotherObjectType = module.component() 236 | 237 | func testRst() -> String { 238 | "SomeViewController.testRst|" + someObject.testAbc() 239 | } 240 | 241 | func testRstNested() -> String { 242 | "SomeViewController.testRstNested|" + anotherObject.testXyz() 243 | } 244 | } 245 | 246 | struct WidgetWorker: WidgetWorkerType { 247 | private let store: WidgetStore 248 | private let remote: WidgetRemote 249 | 250 | init(store: WidgetStore, remote: WidgetRemote) { 251 | self.store = store 252 | self.remote = remote 253 | } 254 | 255 | func fetch(id: Int) -> String { 256 | store.fetch(id: id) 257 | + remote.fetch(id: id) 258 | } 259 | } 260 | 261 | struct WidgetNetworkRemote: WidgetRemote { 262 | private let httpService: HTTPServiceType 263 | 264 | init(httpService: HTTPServiceType) { 265 | self.httpService = httpService 266 | } 267 | 268 | func fetch(id: Int) -> String { 269 | "|MediaNetworkRemote.\(id)|" 270 | } 271 | } 272 | 273 | struct WidgetRealmStore: WidgetStore { 274 | 275 | func fetch(id: Int) -> String { 276 | "|MediaRealmStore.\(id)|" 277 | } 278 | 279 | func createOrUpdate(_ request: String) -> String { 280 | "MediaRealmStore.createOrUpdate\(request)" 281 | } 282 | } 283 | 284 | struct HTTPService: HTTPServiceType { 285 | 286 | func get(url: String) -> String { 287 | "HTTPService.get" 288 | } 289 | 290 | func post(url: String) -> String { 291 | "HTTPService.post" 292 | } 293 | } 294 | 295 | // MARK: API 296 | 297 | protocol WidgetModuleType { 298 | func component() -> WidgetWorkerType 299 | func component() -> WidgetRemote 300 | func component() -> WidgetStore 301 | func component() -> HTTPServiceType 302 | func test() -> String 303 | } 304 | 305 | protocol SampleModuleType { 306 | func component() -> SomeObjectType 307 | func component() -> AnotherObjectType 308 | func component() -> ViewModelObjectType 309 | func component() -> ViewControllerObjectType 310 | func test() -> String 311 | } 312 | 313 | protocol SomeObjectType { 314 | func testAbc() -> String 315 | } 316 | 317 | protocol AnotherObjectType { 318 | func testXyz() -> String 319 | } 320 | 321 | protocol ViewModelObjectType { 322 | func testLmn() -> String 323 | func testLmnNested() -> String 324 | } 325 | 326 | protocol ViewControllerObjectType { 327 | func testRst() -> String 328 | func testRstNested() -> String 329 | } 330 | 331 | protocol WidgetStore { 332 | func fetch(id: Int) -> String 333 | func createOrUpdate(_ request: String) -> String 334 | } 335 | 336 | protocol WidgetRemote { 337 | func fetch(id: Int) -> String 338 | } 339 | 340 | protocol WidgetWorkerType { 341 | func fetch(id: Int) -> String 342 | } 343 | 344 | protocol HTTPServiceType { 345 | func get(url: String) -> String 346 | func post(url: String) -> String 347 | } 348 | ``` 349 | This way, only your "modules" are not type-safe, which is acceptable since 350 | an exception with a missing module should happen early on and hopefully 351 | obvious enough in development. 352 | 353 | However, the individual components are type-safe and have greater flexiblity to include 354 | parameters while resolving the component. The components should have their dependencies 355 | injected through the constructor, which is the best form of dependency injection. 356 | The modules get the property wrappers support and can even inject modules within modules. 357 | -------------------------------------------------------------------------------- /Sources/Shank/Shank.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Shank 3 | // A Swift micro-library that provides lightweight dependency injection. 4 | // 5 | // Inspired by: 6 | // https://dagger.dev 7 | // https://github.com/hmlongco/Resolver 8 | // https://github.com/InsertKoinIO/koin 9 | // 10 | // Created by Basem Emara on 2019-09-06. 11 | // Copyright © 2019 Zamzam Inc. All rights reserved. 12 | // 13 | 14 | import Foundation 15 | 16 | /// A dependency collection that provides resolutions for object instances. 17 | open class Dependencies { 18 | /// Stored object instance factories. 19 | private var modules = [String: Module]() 20 | 21 | /// Construct dependency resolutions. 22 | public init(@ModuleBuilder _ modules: () -> [Module]) { 23 | modules().forEach { add(module: $0) } 24 | } 25 | 26 | /// Construct dependency resolution. 27 | public init(@ModuleBuilder _ module: () -> Module) { 28 | add(module: module()) 29 | } 30 | 31 | /// Assigns the current container to the composition root. 32 | open func build() { 33 | Self.root = self 34 | } 35 | 36 | fileprivate init() {} 37 | deinit { modules.removeAll() } 38 | } 39 | 40 | private extension Dependencies { 41 | /// Composition root container of dependencies. 42 | static var root = Dependencies() 43 | 44 | /// Registers a specific type and its instantiating factory. 45 | func add(module: Module) { 46 | modules[module.name] = module 47 | } 48 | 49 | /// Resolves through inference and returns an instance of the given type from the current default container. 50 | /// 51 | /// If the dependency is not found, an exception will occur. 52 | func resolve(for name: String? = nil) -> T { 53 | let name = name ?? String(describing: T.self) 54 | 55 | guard let component: T = modules[name]?.resolve() as? T else { 56 | fatalError("Dependency '\(T.self)' not resolved!") 57 | } 58 | 59 | return component 60 | } 61 | } 62 | 63 | // MARK: Public API 64 | 65 | public extension Dependencies { 66 | 67 | /// DSL for declaring modules within the container dependency initializer. 68 | @_functionBuilder struct ModuleBuilder { 69 | public static func buildBlock(_ modules: Module...) -> [Module] { modules } 70 | public static func buildBlock(_ module: Module) -> Module { module } 71 | } 72 | } 73 | 74 | /// A type that contributes to the object graph. 75 | public struct Module { 76 | fileprivate let name: String 77 | fileprivate let resolve: () -> Any 78 | 79 | public init(_ name: String? = nil, _ resolve: @escaping () -> T) { 80 | self.name = name ?? String(describing: T.self) 81 | self.resolve = resolve 82 | } 83 | } 84 | 85 | /// Resolves an instance from the dependency injection container. 86 | @propertyWrapper 87 | public class Inject { 88 | private let name: String? 89 | private var storage: Value? 90 | 91 | public var wrappedValue: Value { 92 | storage ?? { 93 | let value: Value = Dependencies.root.resolve(for: name) 94 | storage = value // Reuse instance for later 95 | return value 96 | }() 97 | } 98 | 99 | public init() { 100 | self.name = nil 101 | } 102 | 103 | public init(_ name: String) { 104 | self.name = name 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Tests/ShankTests/ShankTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Shank 3 | 4 | final class DependencyTests: XCTestCase { 5 | 6 | private static let dependencies = Dependencies { 7 | Module { WidgetModule() as WidgetModuleType } 8 | Module { SampleModule() as SampleModuleType } 9 | Module("abc") { SampleModule(value: "123") as SampleModuleType } 10 | Module { SomeClass() as SomeClassType } 11 | } 12 | 13 | @Inject private var widgetModule: WidgetModuleType 14 | @Inject private var sampleModule: SampleModuleType 15 | @Inject("abc") private var sampleModule2: SampleModuleType 16 | @Inject private var someClass: SomeClassType 17 | 18 | private lazy var widgetWorker: WidgetWorkerType = widgetModule.component() 19 | private lazy var someObject: SomeObjectType = sampleModule.component() 20 | private lazy var anotherObject: AnotherObjectType = sampleModule.component() 21 | private lazy var viewModelObject: ViewModelObjectType = sampleModule.component() 22 | private lazy var viewControllerObject: ViewControllerObjectType = sampleModule.component() 23 | 24 | override class func setUp() { 25 | super.setUp() 26 | dependencies.build() 27 | } 28 | } 29 | 30 | // MARK: - Test Cases 31 | 32 | extension DependencyTests { 33 | 34 | func testResolver() { 35 | // Given 36 | let widgetModuleResult = widgetModule.test() 37 | let sampleModuleResult = sampleModule.test() 38 | let sampleModule2Result = sampleModule2.test() 39 | let widgetResult = widgetWorker.fetch(id: 3) 40 | let someResult = someObject.testAbc() 41 | let anotherResult = anotherObject.testXyz() 42 | let viewModelResult = viewModelObject.testLmn() 43 | let viewModelNestedResult = viewModelObject.testLmnNested() 44 | let viewControllerResult = viewControllerObject.testRst() 45 | let viewControllerNestedResult = viewControllerObject.testRstNested() 46 | 47 | // Then 48 | XCTAssertEqual(widgetModuleResult, "WidgetModule.test()") 49 | XCTAssertEqual(sampleModuleResult, "SampleModule.test()") 50 | XCTAssertEqual(sampleModule2Result, "SampleModule.test()123") 51 | XCTAssertEqual(widgetResult, "|MediaRealmStore.3||MediaNetworkRemote.3|") 52 | XCTAssertEqual(someResult, "SomeObject.testAbc") 53 | XCTAssertEqual(anotherResult, "AnotherObject.testXyz|SomeObject.testAbc") 54 | XCTAssertEqual(viewModelResult, "SomeViewModel.testLmn|SomeObject.testAbc") 55 | XCTAssertEqual(viewModelNestedResult, "SomeViewModel.testLmnNested|AnotherObject.testXyz|SomeObject.testAbc") 56 | XCTAssertEqual(viewControllerResult, "SomeViewController.testRst|SomeObject.testAbc") 57 | XCTAssertEqual(viewControllerNestedResult, "SomeViewController.testRstNested|AnotherObject.testXyz|SomeObject.testAbc") 58 | } 59 | 60 | func testNumberOfInstances() { 61 | let instance1 = someClass 62 | let instance2 = someClass 63 | XCTAssertEqual(instance1.id, instance2.id) 64 | } 65 | } 66 | 67 | // MARK: - Subtypes 68 | 69 | extension DependencyTests { 70 | 71 | struct WidgetModule: WidgetModuleType { 72 | 73 | func component() -> WidgetWorkerType { 74 | WidgetWorker( 75 | store: component(), 76 | remote: component() 77 | ) 78 | } 79 | 80 | func component() -> WidgetRemote { 81 | WidgetNetworkRemote(httpService: component()) 82 | } 83 | 84 | func component() -> WidgetStore { 85 | WidgetRealmStore() 86 | } 87 | 88 | func component() -> HTTPServiceType { 89 | HTTPService() 90 | } 91 | 92 | func test() -> String { 93 | "WidgetModule.test()" 94 | } 95 | } 96 | 97 | struct SampleModule: SampleModuleType { 98 | let value: String? 99 | 100 | init(value: String? = nil) { 101 | self.value = value 102 | } 103 | 104 | func component() -> SomeObjectType { 105 | SomeObject() 106 | } 107 | 108 | func component() -> AnotherObjectType { 109 | AnotherObject(someObject: component()) 110 | } 111 | 112 | func component() -> ViewModelObjectType { 113 | SomeViewModel( 114 | someObject: component(), 115 | anotherObject: component() 116 | ) 117 | } 118 | 119 | func component() -> ViewControllerObjectType { 120 | SomeViewController() 121 | } 122 | 123 | func test() -> String { 124 | "SampleModule.test()\(value ?? "")" 125 | } 126 | } 127 | 128 | struct SomeObject: SomeObjectType { 129 | func testAbc() -> String { 130 | "SomeObject.testAbc" 131 | } 132 | } 133 | 134 | class SomeClass: SomeClassType { 135 | let id: String 136 | 137 | init() { 138 | self.id = UUID().uuidString 139 | } 140 | } 141 | 142 | struct AnotherObject: AnotherObjectType { 143 | private let someObject: SomeObjectType 144 | 145 | init(someObject: SomeObjectType) { 146 | self.someObject = someObject 147 | } 148 | 149 | func testXyz() -> String { 150 | "AnotherObject.testXyz|" + someObject.testAbc() 151 | } 152 | } 153 | 154 | struct SomeViewModel: ViewModelObjectType { 155 | private let someObject: SomeObjectType 156 | private let anotherObject: AnotherObjectType 157 | 158 | init(someObject: SomeObjectType, anotherObject: AnotherObjectType) { 159 | self.someObject = someObject 160 | self.anotherObject = anotherObject 161 | } 162 | 163 | func testLmn() -> String { 164 | "SomeViewModel.testLmn|" + someObject.testAbc() 165 | } 166 | 167 | func testLmnNested() -> String { 168 | "SomeViewModel.testLmnNested|" + anotherObject.testXyz() 169 | } 170 | } 171 | 172 | class SomeViewController: ViewControllerObjectType { 173 | @Inject private var module: SampleModuleType 174 | 175 | private lazy var someObject: SomeObjectType = module.component() 176 | private lazy var anotherObject: AnotherObjectType = module.component() 177 | 178 | func testRst() -> String { 179 | "SomeViewController.testRst|" + someObject.testAbc() 180 | } 181 | 182 | func testRstNested() -> String { 183 | "SomeViewController.testRstNested|" + anotherObject.testXyz() 184 | } 185 | } 186 | 187 | struct WidgetWorker: WidgetWorkerType { 188 | private let store: WidgetStore 189 | private let remote: WidgetRemote 190 | 191 | init(store: WidgetStore, remote: WidgetRemote) { 192 | self.store = store 193 | self.remote = remote 194 | } 195 | 196 | func fetch(id: Int) -> String { 197 | store.fetch(id: id) 198 | + remote.fetch(id: id) 199 | } 200 | } 201 | 202 | struct WidgetNetworkRemote: WidgetRemote { 203 | private let httpService: HTTPServiceType 204 | 205 | init(httpService: HTTPServiceType) { 206 | self.httpService = httpService 207 | } 208 | 209 | func fetch(id: Int) -> String { 210 | "|MediaNetworkRemote.\(id)|" 211 | } 212 | } 213 | 214 | struct WidgetRealmStore: WidgetStore { 215 | 216 | func fetch(id: Int) -> String { 217 | "|MediaRealmStore.\(id)|" 218 | } 219 | 220 | func createOrUpdate(_ request: String) -> String { 221 | "MediaRealmStore.createOrUpdate\(request)" 222 | } 223 | } 224 | 225 | struct HTTPService: HTTPServiceType { 226 | 227 | func get(url: String) -> String { 228 | "HTTPService.get" 229 | } 230 | 231 | func post(url: String) -> String { 232 | "HTTPService.post" 233 | } 234 | } 235 | } 236 | 237 | // MARK: API 238 | 239 | protocol WidgetModuleType { 240 | func component() -> WidgetWorkerType 241 | func component() -> WidgetRemote 242 | func component() -> WidgetStore 243 | func component() -> HTTPServiceType 244 | func test() -> String 245 | } 246 | 247 | protocol SampleModuleType { 248 | func component() -> SomeObjectType 249 | func component() -> AnotherObjectType 250 | func component() -> ViewModelObjectType 251 | func component() -> ViewControllerObjectType 252 | func test() -> String 253 | } 254 | 255 | protocol SomeObjectType { 256 | func testAbc() -> String 257 | } 258 | 259 | protocol AnotherObjectType { 260 | func testXyz() -> String 261 | } 262 | 263 | protocol SomeClassType { 264 | var id: String { get } 265 | } 266 | 267 | protocol ViewModelObjectType { 268 | func testLmn() -> String 269 | func testLmnNested() -> String 270 | } 271 | 272 | protocol ViewControllerObjectType { 273 | func testRst() -> String 274 | func testRstNested() -> String 275 | } 276 | 277 | protocol WidgetStore { 278 | func fetch(id: Int) -> String 279 | func createOrUpdate(_ request: String) -> String 280 | } 281 | 282 | protocol WidgetRemote { 283 | func fetch(id: Int) -> String 284 | } 285 | 286 | protocol WidgetWorkerType { 287 | func fetch(id: Int) -> String 288 | } 289 | 290 | protocol HTTPServiceType { 291 | func get(url: String) -> String 292 | func post(url: String) -> String 293 | } 294 | --------------------------------------------------------------------------------