Last active
June 17, 2020 13:03
-
-
Save fumiyasac/327f21eb8834931c3bc1c45c2b03b84d to your computer and use it in GitHub Desktop.
PropertyWrapperを利用したDependendyInjectionの例(定義側)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
// MEMO: Swift5.1から登場した「Property Wrappers」を利用したDependency Injectionの実装例 | |
// https://stackoverflow.com/questions/61316547/nested-dependency-injection-through-property-wrapper-crashes | |
// 補足: Property Wrappersについて | |
// https://dev.classmethod.jp/articles/property-wrappers/ | |
enum Dependencies { | |
// MARK: - Struct (for Name of Dependencies) | |
struct Name: Equatable { | |
let rawValue: String | |
static let `default` = Name(rawValue: "__default__") | |
static func == (lhs: Name, rhs: Name) -> Bool { lhs.rawValue == rhs.rawValue } | |
} | |
// MARK: - Class (for Container) | |
final class Container { | |
private var dependencies: [(key: Dependencies.Name, value: Any)] = [] | |
static let `default` = Container() | |
// MARK: - Function | |
// MEMO: 依存関係があるものを登録する | |
func register(_ dependency: Any, for key: Dependencies.Name = .default) { | |
dependencies.append((key: key, value: dependency)) | |
} | |
// MEMO: 引数に与えた名前を元にDIを実行する | |
func resolve<T>(_ key: Dependencies.Name = .default) -> T { | |
// Debug. | |
//dump(dependencies) | |
// MEMO: 名前と依存関係を正しく対応させないとクラッシュが発生する形にしている | |
return (dependencies | |
.filter { (dependencyTuple) -> Bool in | |
dependencyTuple.key == key | |
&& dependencyTuple.value is T | |
} | |
.first)?.value as! T | |
/* | |
// <別解> | |
// MEMO: filterとfirstをするよりもfirst(where:)の方がパフォーマンスが良い | |
// https://qiita.com/shtnkgm/items/928630d692cf1e5b0846 | |
let instanceObjectValue = dependencies | |
// MEMO: 引数のkeyと一致する&型がTに設定している条件に合致する場合はその値 (.value)だけを利用する | |
.first { (dependencyTuple) -> Bool in | |
dependencyTuple.key == key && dependencyTuple.value is T | |
} | |
.flatMap{ (_, value) in | |
value | |
} | |
// MEMO: 名前に対応する型でダウンキャストを実施し、名前と依存関係を正しく対応させないとクラッシュが発生する形にしている | |
guard let instance = instanceObjectValue as? T else { | |
fatalError("Could not cast value of type 'Any' to expected type.") | |
} | |
return instance | |
*/ | |
} | |
} | |
// MARK: - @propatyWrapper (for Struct for Dependency Injection) | |
@propertyWrapper | |
struct Inject<T> { | |
private let dependencyName: Name | |
private let container: Container | |
// 設定した名前を元に依存関係の解決を実施する | |
var wrappedValue: T { container.resolve(dependencyName) } | |
// MARK: - Initializer | |
init(_ dependencyName: Name = .default, on container: Container = .default) { | |
self.dependencyName = dependencyName | |
self.container = container | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment