Open1

【Swift】unwrap済みのoptionalな値を利用する際、コンパイルエラーで再度unwrapを求められることがある

ダンボー田中ダンボー田中

起きたこと

次のようなRxSwiftを利用したコードで Value of optional type "SomeType?" must be unwrapped to refer to member "someProperty" of wrapped base type "SomeType" というコンパイルエラーが出ました。

FluxのStoreにあるBehaviorRelayの値を、flatMapでunwrapしてUI側で利用するサンプルコードです。

store.$someStoredProperty
  .flatMap { Observable.from(optional: $0) }
  .asDriver(onErrorDriveWith: .empty())
  .drive(Binder(self) { target, someProperty in
    target.doSomethingA(someProperty) // `Value of optional type "SomeStoredType?" must be unwrapped to refer to member "someProperty" of wrapped base type "SomeStoredType"`
    target.doSomethingB()
  }).disposed(by: bag)

driveの中で利用しているsomePropertyはすでにunwrapされた値なので、このエラーには違和感があります。
実はこれ、後述するコードに誤りがあるとなぜかunwrapされたsomePropertyを利用している箇所にこのエラーが出るようです。

このサンプルコードで誤りとなるのは target.doSomethingB() の部分。
書き換えのタイミングで doSomethingB の関数を削除してしまっており、正しく出てほしいエラーは次のように Cannot find "doSomething" in scope となります。

target.doSomethingB() // `Cannot find "doSomethingB" in scope`

そのためこの問題は target.doSomethingB() を削除すればunwrapを求めるエラーが解消されます。

再現した環境

  • Xcode 15.0
  • RxSwift 6.0.0

その他検証

unwrapした値を利用するコードで、スコープ内に関数の定義がない関数の呼び出しを行ってみました。
すると、正しいエラーが表示されました。

func doSomethingA(int: Int?) {}

func someLifeCycle() {
    var hoge: Int?
    if let hoge = hoge {
      doSomethingA(int: hoge)
      doSomethingB() // `Cannot find "doSomethingB" in scope`
    }
}

その他考えられること

  • RxSwiftのバージョンが古い。