RxSwiftで循環参照してるかもしれない書き方

RxSwiftというよりは、Swiftの話です。

そもそもSwiftの機能として、クロージャの引数とマッチするパラメーターを持つ関数は、 `rxSwift.bind(onNext: multiply)` のようにクロージャに引数として渡して使えるようなのですが、「これ、簡潔に書けるけど、循環参照って起こったりしないの？」と思ったので検証しました。

こちら参考にさせていただきました。
[RxSwiftでクロージャも無いのにメモリリークさせてた](https://qiita.com/t-ae/items/681f839e33c10ad61876)


# ソースコード

RxSwiftっぽい感じにして簡単に検証しました。

```swift:source.swift
import Foundation

class ViewController {
    
    var intValue: Int
    let rxSwift = RxSwift()
    
    init(initialValue: Int) {
        self.intValue = initialValue
        print("ViewController init")
    }
    
    deinit {
        print("ViewController deinit")
    }
    
    func multiply(by: Int) {
        intValue *= by
        
        print("value is \(intValue)")
    }
    
    func multiplyNothing(by: Int) {
        // Do nothing
    }
    
    func start() {
        rxSwift.bind(onNext: multiply)
    }
    
    func startNothing() {
        rxSwift.bind(onNext: multiplyNothing)
    }
    
    func startWeakRef() {
        rxSwift.bind(onNext: { [weak self] value in
            self?.multiply(by: value)
        })
    }
    
    func startWeakRefDirect() {
        rxSwift.bind(onNext: { [weak self] value in
            self?.intValue *= value
            print("value is \(self?.intValue)")
        })
    }
    
}

class RxSwift {
    
    var _onNext: ((Int) -> Void)?
    private var _value: Int = 0
    var value: Int {
        
        get {
            return _value
        }
        
        set (newValue){
            _value = newValue
            _onNext?(_value)
        }
        
    }
    
    init() {
        print("RxSwift init")
    }
    
    deinit {
        print("RxSwift deinit")
    }
    
    func bind(onNext: @escaping ((Int) -> Void)) {
        _onNext = onNext
    }
    
}

```

# 検証1. 「内部でselfを参照する関数をクロージャの引数に渡す」

```swift:strong-ref.swift
var vc: ViewController? = ViewController(initialValue: 3)
vc?.start()
vc?.rxSwift.value = 5
vc = nil

// RxSwift init
// ViewController init
// value is 15

```

<font color="Red">**循環参照する**</font>

# 検証2. 「selfをキャプチャするクロージャをweak selfで実行する」
```swift:weak-ref-direct.swift

var vc: ViewController? = ViewController(initialValue: 3)
vc?.startWeakRefDirect()
vc?.rxSwift.value = 5
vc = nil

// RxSwift init
// ViewController init
// value is 15
// ViewController deinit
// RxSwift deinit

```

**循環参照しない**

# 検証3. 「内部でselfを参照する関数をクロージャの引数に渡す」
```swift:weak-ref.swift

var vc: ViewController? = ViewController(initialValue: 3)
vc?.startWeakRef()
vc?.rxSwift.value = 5
vc = nil

// RxSwift init
// ViewController init
// value is 15
// ViewController deinit
// RxSwift deinit

```

**循環参照しない**

# 検証4. 「内部で**selfを参照しない**関数をクロージャの引数に渡す」

```swift:start-nothing.swift

var vc: ViewController? = ViewController(initialValue: 3)
vc?.startNothing()
vc?.rxSwift.value = 5
vc = nil

// RxSwift init
// ViewController init

```

<font color="Red">**循環参照する**</font>

# なぜか
selfがキャプチャされるから。(当たり前)

普段コンパイラに頼りきっていて、「[weak self]をつけろって言われない書き方出来てるし、これで大丈夫やろ！」と思ってしまいそうになりますが、`@escaping` かどうかはちゃんと見るようにしましょう(自戒

# 本家のbind(onNext:)
ちゃんと`@escaping`書かれてて強参照が明示的になってますね。

```swift:bind.swift
/**
        Subscribes an element handler to an observable sequence. 
    
        In case error occurs in debug mode, `fatalError` will be raised.
        In case error occurs in release mode, `error` will be logged.
        
        - parameter onNext: Action to invoke for each element in the observable sequence.
        - returns: Subscription object used to unsubscribe from the observable sequence.
        */
    public func bind(onNext: @escaping (Self.E) -> Swift.Void) -> Disposable

```

# どうすれば良いのか
関数に処理を切り出すにしても、selfを参照するコードは全て[weak self]にしておくと間違い無いです。
([unowned self]でもいいという記事も見かけたので、絶対そうとは言い切りません)