3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

swift-dependencies で Key に引数を渡す

Posted at

Pointfree の提供している swift-dependenciesですが、非常に利用方法も簡単で、テスト時の利用など使い勝手の良いものになっています。

しかし、 riverpod の Provider にできるように、引数を渡してその引数に応じた値を取得できるようにしたい場合はないでしょうか?

例:

ref.watch(activityProvider('recreational'))

このようなあると便利な機能を swift-dependencies でどう実現するのか、その方法を考えて利用してみたので、その方法を共有します。

(自分の)結論

こちらの discussion で提案されているようなやり方で指定できるようにしました。

@Dependency(\.hoge[.paramA]) var hoge

実現の仕方

具体的には、 DependencyValueContainer という class を作ってあげて、これを @Dependency で指定して取得する値の型にします。

final class DependencyValueContainer<Value, Argument> where Argument: Hashable {
    fileprivate var values: [Argument: Value] = [:]
    var create: (Argument) -> Value

    public init(create: @escaping (Argument) -> Value) {
        self.create = create
    }

    public subscript(argument: Argument) -> Value {
        if let value = values[argument] {
            return value
        }

        let newValue = create(argument)
        values[argument] = newValue
        return newValue
    }
}

swift-dependencies は DependencyValues に登録した値が持っているプロパティなどにアクセスし、その値を取り出してあげることもできるので、その仕組みを利用するイメージです。

依存関係の登録例:

private enum HogeContainerKey: DependencyKey {
    static var liveValue: DependencyValueContainer<Hoge, ParamA> {
        DependencyValueContainer { argument in
            return Hoge(argument: argument)
        }
    }
}

extension DependencyValues {
    public var hoge: DependencyValueContainer<Hoge, ParamA> {
        get { self[HogeContainerKey.self] }
        set { self[HogeContainerKey.self] = newValue }
    }
}

こうすると、冒頭にあったように以下のように値を取り出すことができるようになります。

@Dependency(\.hoge[.paramA]) var hoge

他の候補

クロージャ

欲しい値を引数を与えると作ってくれるクロージャを DependencyValues に登録する手法です

イメージ:

private enum HogeContainerKey: DependencyKey {
    typealias HogeCreate = (ParamA) -> Hoge
    static var liveValue: HogeCreate = { paramA in
        Hoge(paramA)
    }
}

使い方次第ですが、使う箇所ごとに毎回別のインスタンスが生成されてしまうことから、この手法はやめました。

initialize のような関数を用意する

初期化用関数を生やす方法ですが、あまり綺麗ではないのと、呼び忘れてランタイムにクラッシュすることに気づきにくいため、やめました。

Hoge.swift
lazy var paramA: ParamA

func initialize(paramA: ParamA) {
    self.paramA = paramA
}

対象のクラスの関数すべてに共通のパラメータを渡せるようにする

名前の通りです。
可能ならこの方法でやるのが一番なのですが、今回元となった対応箇所では20個ほど共通の関数があるのと、 var で定義されていた computed property 等も中でそのパラメータを利用していたため、対応自体の大変さから見送りました。

終わりに

今回は swift-dependencies の key に引数を渡す(風)の方法を紹介してみました。
DI の方法を何かしらから変えていくような場合には欲しくなる場面もあるかもしれないので、もしそんな場面に遭遇したら試してみてもらえるとありがたいです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?