Swiftのクロージャにおける循環参照問題でunownedとweakの使い分けがわからない



## 追記について

追記が増えたので以下の記事を新たに作成しました。こちらと合わせてご参照ください。

[Swiftの循環参照問題におけるunownedとweakの使い分けについて](http://qiita.com/susieyy/items/f57f9362b8e0a89023cb)


## はじめに

クロージャーは定義したスコープの定数や変数をキャプチャすることができます。このキャプチャのおかげでインスタンス変数を定義して、値を保持する必要がなくケースがあるので便利に活用しています。ただキャプチャ値を利用する場合は、循環参照を考慮したコードを記述する必要があります。循環参照に陥ると双方のインスタンスがメモリ上から開放されず、メモリリークの原因になります。

## クロージャの循環参照と回避方法

クロージャが循環参照をしている例です。

`self`がクロージャを強参照し、クロージャが`self`を強参照して循環参照に陥っています。

-  `HTMLElement`インスタンスは`asHTML`プロパティで`() -> String`クロージャを強参照にてインスタンスを保持している 
- `() -> String`クロージャは`HTMLElement`インスタンスを`self`として強参照している


![The_Swift_Programming_Language__Automatic_Reference_Counting.jpg](https://qiita-image-store.s3.amazonaws.com/0/4943/c29cc158-ad81-df5e-1e12-8612b75d7ea6.jpeg "The_Swift_Programming_Language__Automatic_Reference_Counting.jpg")


コードでは以下のようになります。`[unowned self]`というキャプチャリストを記述することでキャプチャした`self` （`HTMLElement`インスタンス）をクロージャは`self`を強参照しなくなります。

強参照を回避するためには`unowned`とは別に`weak`もあります。
`unowned`と`weak`の違いはキャプチャする変数の値がnilになりえる時(Optional)は`weak`、値が常に存在する場合は`unowned`になります。

```Swift
class HTMLElement {
    
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        [unowned self] in // <- Unowned References
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        println("\(name) is being deinitialized")
    }
    
}
```

Appleの公式ドキュメントより [Swift Automatic Reference Counting](https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)

# 以下わからないころの紆余曲折な内容です

コメント欄の議論の原点なので残しておきます。

こちらの内容をご参照ください。
[Swiftの循環参照問題におけるunownedとweakの使い分けについて](http://qiita.com/susieyy/items/f57f9362b8e0a89023cb)


## unownedとweakの使い分けがわからない

例えば、UIViewControllerのselfをキャプチャする場合は、`unowned`と`weak`のどちらを記述すればよいのかよくわかりません。
キャプチャする変数の定義にOptionalが明示的に宣言されていればわかりやすいのですが。

クロージャがUIViewControllerを`self`としてキャプチャしているところを`unowned`で記述するとクラッシュしてしまいます。`weak`だとクラッシュしません。`self`はUnwrapせずにアクセスするのでOptionalではないと思うのですが、`weak`を記述することが正しいのでしょうか。

<strong><span style="color:#ff0000;">【追記】このクラッシュの事象はBeta6では改善されているようです。Beta5では発生していました。</span></strong>

### 実行時エラー (Beta6では改善済）




クラッシュすると以下のようなエラーが出ます。

![news-simple-app_xcworkspace.jpg](https://qiita-image-store.s3.amazonaws.com/0/4943/83a78964-8cb2-9a99-1e00-2537bcaf1934.jpeg "news-simple-app_xcworkspace.jpg")


同じ境遇の方も。。。

<blockquote class="twitter-tweet" lang="ja"><p>今度は swift_unknownRetainUnowned でクラッシュ。 [unowned self]が原因なのは間違いないんですが、これを使ってはいけないケースがあるということなのかな・・・理解が甘い・・・</p>&mdash; akisute (@akisutesama) <a href="https://twitter.com/akisutesama/statuses/499855424519028736">2014, 8月 14</a></blockquote>

### コード例

BlocksKitを使っています。`self`はUIViewControllerのインスタンスです。

```Swift
/// unowned は クロージャをセット時にクラッシュ
button.bk_addEventHandler({ [unowned self] (sender: AnyObject!) in
    self.navigationController.pushViewController("HOGE", animated: true)    
}, forControlEvents: UIControlEvents.TouchUpInside)

/// weak は OK 
button.bk_addEventHandler({ [weak self] (sender: AnyObject!) in
    if let selfWeak = self {
        selfWeak.navigationController.pushViewController("HOGE", animated: true)
    }
}, forControlEvents: UIControlEvents.TouchUpInside)

```

### 【追記】「初期化後にnilである可能性がある」場合には、unownedではなく、weakを使うべき

~~UIViewControllerの`self`においては、クロージャ実行時に`self`がnilになる可能性があるので`weak`を使うのがよさそうです。~~

UIViewControllerの`self`においては、どのケースでどちらを利用すればよいか確認中です。
Beta5では`unowned`を利用するとクラッシュしていたので、`weak`を使うべきと判断していたのですが、Beta6ではクラッシュが改善されており`unowned`も記述はできるためです。

#### 判断基準について

コメント欄にて、@tomohisaota さんよりご教授頂きました。ありがとうございます。
@tomohisaota さんのQiita投稿でdelegateの場合ですが、`unowned`と`weak`について丁寧に解説してくださっているのでそちらも合わせてご参照ください。


#### 参考1 @tomohisaota さんのコメントより

>弱参照は常にweakをつかって、nilになる可能性を意識して書けばOKです。
unownedとweakの最大の違いは、オブジェクト破棄時にnilクリアされるかどうかです。
unownedはnilクリアされないので、オブジェクト破棄後にアクセスすると落ちます。
weakはnilクリアされるので、オブジェクト破棄後にアクセスしてもnilになります。

>unownedを使うのは、オブジェクトの生成タイミングをきっちり把握していて、絶対にブロック実行時にインスタンスが破棄されていないことが確信できる場合のみです。
その場合であっても、weak使ってはいけないわけじゃないので、迷うならweak一択です。

#### 参考2 @tomohisaota さんのQiita投稿

[なぜdelegateはunowned(unsafe)+Implicitly Unwrappedなの？](http://qiita.com/tomohisaota/items/af48e75798fdc05e19c7)

> そもそも「初期化後にnilである可能性がある」場合には、unownedではなく、weakを使うべきです。


## キャプチャリストを記述すべきかわからない

【追記】プロパティの`get`,　`set`, `willSet`, `didSet`はクロジャーではないので、キャプチャリストは不要です。

~~プロパティの`get`,　`set`, `willSet`, `didSet`で参照する`self`はキャプチャリストが必要かわからないです。~~

```Swift
override var description: String! {
    get {
        return "\(self.title) \(self.url)"
    }
}


var title: String! {
	didSet {
		println(self.description)		
	}
}
```

### unownedの場合のエラー

![WTDArticleView_swift_—_Edited.jpg](https://qiita-image-store.s3.amazonaws.com/0/4943/62ebc702-eedb-1264-afb5-6abd1282c38b.jpeg "WTDArticleView_swift_—_Edited.jpg")


### weakの場合のエラー

![WTDArticleView_swift.jpg](https://qiita-image-store.s3.amazonaws.com/0/4943/2a6c9379-8fbe-e2ac-7575-6b75f157c29f.jpeg "WTDArticleView_swift.jpg")



### 他にも困っている方が。。。

<blockquote class="twitter-tweet" lang="ja"><p>[unowned self] inの使い方がわからない。どうやってもコンパイルエラーになる</p>&mdash; yoshinori.imajo (@yimajo) <a href="https://twitter.com/yimajo/statuses/475217302820880384">2014, 6月 7</a></blockquote>

<blockquote class="twitter-tweet" lang="ja"><p>そもそもクロージャ内で[weak self]または[unowned self]をやろうとするとエラーになる...XCode Beta1で作ったプロジェクトだから・・・？ちなみにplaygroundでは動作する模様。 <a href="https://twitter.com/hashtag/swift?src=hash">#swift</a></p>&mdash; 借りぐらしのkazuki (@kz_kazuki) <a href="https://twitter.com/kz_kazuki/statuses/488222999665856512">2014, 7月 13</a></blockquote>



## 実行環境

- Xcode6 Beta5
- iOS7.1 iPhone5 実機
- iOS8.0 Beta5 iPhone5s シミュレータ
- iOS8.0 Beta5 iPhone5 シミュレータ




## 参考資料
- [GithubのSwiftでリポジトリでunownedを含む検索結果](https://github.com/search?l=Swift&q=unowned&ref=advsearch&type=Code&utf8=%E2%9C%93)
- [Twitterでunownedを含む検索結果](https://twitter.com/search?f=realtime&q=lang%3Aja%20unowned&src=typd)
- [Shall we always use [unowned self] inside closure in Swift](http://stackoverflow.com/questions/24320347/shall-we-always-use-unowned-self-inside-closure-in-swift)