LoginSignup
13
10

More than 5 years have passed since last update.

unownedの使いどころ

Posted at

Swiftでクロージャーを利用する場合、循環参照をしないようにself(場合によってはself以外の変数も)を弱参照にしますが、その時weak or unownedどちらにするべきか迷うことがあると思います。
基本的には困ったらweakにして置くのがベターですが、unownedを使えれば記述も少し短くなるのでその例を紹介します。

unownedを使える条件

循環参照するかつクロージャーが呼ばれる時にその対象が解放されていない場合です。
解放されている状態で万が一その対象にアクセスするとクラッシュします。

クラッシュする例

class SomeVC: UIViewController {
    func apiRequest() {
       Session().send() {[unowned self] in
           // ネットワークの状況によっては数秒後にクロージャーがコールされる
           // Backボタン等でこのVCが解放されていたらselfにアクセスした時点でクラッシュする
           self.handleAPIResponse()
       }
    }
}

クロージャーの呼び出される期間がオブジェクトの生存期間と同じであればこのようなことは起きませんが、ネットワークアクセスやアプリで使い回すシングルトンのモジュールなどはどうしても生存期間が違ってきます。

unownedを使えるパターン

パターン1:オブジェクトの解放されるタイミングで明示的にクロージャーの呼び出しを無効化する場合

class SomeVC: UIViewController {
    var task: SessionTask?
    var object = Object()
    deinit {
        task?.cancel()
        object.completion = nil
    }
    func apiRequest() {
       task = Session().send() {[unowned self] in
           // ネットワークの状況によっては数秒後にクロージャーがコールされる
           // deinitでcancelされてるのでselfが解放されるとここは呼ばれないのでクラッシュしない
           self.handleAPIResponse()
       }

       object.completion = {[unowned self] in 
           // deinitでobject.completionにnilを代入しているので解放後ここは呼ばれずクラッシュしない
           self.someAction()
       }
       object.longTimeMethod()
    }
}

パターン2:オブジェクトの生存期間とクロージャーの呼び出される期間が同じ場合

通常のSwiftではあまりないですが、RxSwiftを使う時に使えます。

import RxSwift
class SomeVC: UIViewController {
    let vm = SomeViewModel()
    let disposeBag = DisposeBag()
    func viewDidLoad() {
        vm.observableObj.subscribe(onNext: { [unowned self] (_) in
            // disposeBagが解放されると、このクロージャーも無効化されるので解放後ここは呼ばれずクラッシュしない
            self.someMethod()
        }).addDisposableTo(disposeBag)
    }
}

パターン1はdeinitに毎回書くのがめんどいのであまりやりませんが、unownedを使うとselfに直接アクセスでき、ちょっとだけ記述が楽になるので問題がない時は積極的に使ってみるのもいいと思います。

13
10
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
13
10