---
title: swift-dependenciesによるDI
tags:  #ios #関モバ  
author: [USAMI Kosuke](https://www.docswell.com/user/usami-k)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/GJ5GYGZMJ4.jpg?width=480
description: 関西モバイルアプリ研究会A #2 - connpass https://kanmoba.connpass.com/event/308691/  DIライブラリswift-dependenciesの話をしました #関モバ - usami-kの日記 https://usami-k.hatenablog.com/entry/2024/02/29/233722
published: February 29, 24
canonical: https://www.docswell.com/s/usami-k/KNR6NE-swift-dependencies
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/GJ5GYGZMJ4.jpg)

swift-dependenciesによるDI
structによるインターフェイス定義
宇佐見公輔 / 株式会社ゆめみ
2024-02-29
swift-dependenciesによるDI
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/LE3R5R9975.jpg)

swift-dependenciesとは
Point-FreeによるDI（Dependency Injection）ライブラリ。
https://github.com/pointfreeco/swift-dependencies
バージョン
0.1.0 : 2023年1月
1.0.0 : 2023年7月
1.2.1 : 2024年2月
The Composable Architecture（TCA）の一部でもある。
swift-dependenciesによるDI
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/8EDYDYG8EG.jpg)

参考記事
次の記事が分かりやすいのでオススメ。
swift-dependencies の使い方・メリット・注意点
なお、今回の話では上述の記事に書かれていない点も取り上げる。
swift-dependenciesによるDI
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/V7P6X63WJ8.jpg)

依存オブジェクトの注入
@Dependency
プロパティラッパーを使う。
final class MainViewModel {
@Dependency(\.myAPIClient) private var myAPIClient
// ...
do {
let result = try await myAPIClient.fetch()
}
}
swift-dependenciesによるDI
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/2JV3L349EQ.jpg)

@Environment
との類似
swift-dependenciesの記法は、SwiftUIの
@Environment
と似ている。
struct MainScreen: View {
@Environment(\.openURL) private var openURL
// ...
Button(&quot;Open&quot;) {
openURL(url)
}
}
swift-dependenciesによるDI
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/5EG3X3147L.jpg)

依存オブジェクトの実装
プロトコルで依存オブジェクトのインターフェイスを定義しておく。
protocol MyAPIClientProtocol {
func fetch() async throws -&gt; Int
}
struct MyAPIClient: MyAPIClientProtocol {
func fetch() async throws -&gt; Int {
// ...
return number
}
}
swift-dependenciesによるDI
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/4JQ585DR7P.jpg)

依存オブジェクトの登録
DependencyKey
プロトコルを使う。
private enum MyAPIClientKey: DependencyKey {
static let liveValue: any MyAPIClientProtocol = MyAPIClient()
}
extension DependencyValues {
var myAPIClient: any MyAPIClientProtocol {
get { self[MyAPIClientKey.self] }
set { self[MyAPIClientKey.self] = newValue }
}
}
swift-dependenciesによるDI
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/K74929ZQE1.jpg)

カスタムEnvironmentとの類似
やはり、SwiftUIの
@Environment
の方法と似ている。
struct MyEnvironmentKey: EnvironmentKey {
static let defaultValue: String = &quot;Default value&quot;
}
extension EnvironmentValues {
var myEnvironment: String {
get { self[MyEnvironmentKey.self] }
set { self[MyEnvironmentKey.self] = newValue }
}
}
swift-dependenciesによるDI
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/LJ1KMKRL7G.jpg)

注入するオブジェクトを変更する
テストで使うオブジェクトを
liveValue
以外のものに変更できる。
struct MyAPIClientMock: MyAPIClientProtocol {
// ...
}
private enum MyAPIClientKey: TestDependencyKey {
static let testValue: any MyAPIClientProtocol = unimplemented()
static let previewValue: any MyAPIClientProtocol = MyAPIClientMock()
}
swift-dependenciesによるDI
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/GJWD3D1Q72.jpg)

注入するオブジェクトを個別変更する
withDependencies
で個別変更できる。
let viewModel = withDependencies {
$0.myAPIClient = MyAPIClientMock(fetchResult: .success(42))
} operation: {
MainViewModel()
}
swift-dependenciesによるDI
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/4EZGVGP3J3.jpg)

インターフェイスの定義のしかた
ここまでの方法：プロトコルでインターフェイスを定義。
protocol MyAPIClientProtocol {
func fetch() async throws -&gt; Int
}
推奨：structとクロージャでインターフェイスを定義。
struct MyAPIClient {
var fetch: () async throws -&gt; Int
}
swift-dependenciesによるDI
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/Y76Y5YMZEV.jpg)

依存オブジェクトの実装と登録
@DependencyClient
struct MyAPIClient {
var fetch: () async throws -&gt; Int
}
extension MyAPIClient: DependencyKey {
static var liveValue: MyAPIClient = {
return .init(fetch: {
// ...
return number
})
}()
}
swift-dependenciesによるDI
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/G75GYGZ974.jpg)

@DependencyClient
testValue
マクロ
向けの実装を自動生成してくれる。
@DependencyClient
struct MyAPIClient {
var fetch: () async throws -&gt; Int
}
extension MyAPIClient: TestDependencyKey {
static var testValue = Self()
}
swift-dependenciesによるDI
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/9J2YGYR5JR.jpg)

依存オブジェクトの注入
final class MainViewModel {
@Dependency(MyAPIClient.self) private var myAPIClient
// ...
do {
let result = try await myAPIClient.fetch()
}
}
なお、
DependencyValues
swift-dependenciesによるDI
のextensionは不要。
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/DEYGVGD6EM.jpg)

注入するオブジェクトを変更する
let viewModel = withDependencies {
$0[MyAPIClient.self].fetch = { return 42 }
} operation: {
MainViewModel()
}
ここでも、
DependencyValues
swift-dependenciesによるDI
のextensionは不要。
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/VJNGMGN178.jpg)

メソッドだけの注入
@Dependency(\.myAPIClient.fetch) private var fetch
do {
let result = try await fetch()
}
extension DependencyValues {
var myAPIClient: MyAPIClient { // ←
get { self[MyAPIClient.self] }
set { self[MyAPIClient.self] = newValue }
}
}
この注入方法では、これが必要になる
swift-dependenciesによるDI
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/YE9WNWRYE3.jpg)

structインターフェイスの利点
プロトコルの場合は
、
、
、
とそれぞれ定義が必要。
structの場合は
だけですみ、シンプルになる。
マクロも活用できる。
ただ、メソッドをクロージャで に渡す記法は慣れがいるかも。
MyAPIClientProtocol
MyAPIClientMock
MyAPIClient
MyAPIClientKey
MyAPIClient
@DependencyClient
init
.init(method1: {},
method2: {},
method3: {})
swift-dependenciesによるDI
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/GE8NKNWK7D.jpg)

応用
注入できるスコープは、メソッドや計算プロパティもあり。
func foo() {
@Dependency(MyLogger.self) private var logger
logger.notice(&quot;log messages&quot;)
}
ただし、公式ドキュメントによると、ライブラリを十分に理解してか
ら使うべきとのこと。
ログやトラッキングなどの用途では問題なさそう。
swift-dependenciesによるDI
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/LELPZPNP7R.jpg)

swift-dependenciesまとめ
SwiftUIの
に近い感覚で使える。
structとクロージャによるインターフェイスの実装方法を使うと、
少ない実装コードでDIができる。
注意すべき点もあるので、公式ドキュメントはちゃんと読むことを
推奨。
@Environment
swift-dependenciesによるDI
19


