27691


SwiftでクロージャーからUILabelにアクセスしています。

[code]

    @IBOutlet weak var log: UILabel!
    ・・・
            Alamofire.request(.GET, "http://hoge.com/hoge.php").validate().responseJSON { response in
                switch response.result {
                case .Success:
                    if let jsonData = response.result.value {
                        let json = JSON(jsonData)
                        for (_,value) in json {
                            self.log.text = self.log.text! + "\n" + value[1].string!.stringByRemovingPercentEncoding!
                        }
                    }
                case .Failure(let error):
                    print(error)
                }
            }
    
[/code]

このような場合、クロージャーの中よりself.log.textにアクセスしているため循環参照によりクロージャーが解放されなくメモリリークになることはないのでしょうか。  
もし続くようならメモリリークになるということであれば回避する方法はどのようにすればよろしいでしょうか。

ご存知の方、ご教示のほどよろしくお願いします。


CC BY-SA 3.0
2016-07-17T16:03:43.373
27690
2019-06-29T08:55:16.390
2019-06-29T08:55:16.390
9008
8593
question
swift クロージャ 循環参照
クロージャーから循環参照によるメモリリーク


そのクロージャーは`self`を強参照で保持していますので、後は`self`が(間接的にでも)強参照でそのクロージャーを保持していれば循環参照が発生するということになります。

従って、 **クロージャーをパラメーターに取るメソッドを呼ぶ場合は、常に循環参照を発生させる可能性がある** と思っておいた方がいいでしょう。

Alamofireの場合は、掲載されたコードのような使い方をする限り大丈夫です。また、最近はLeaksのようなツールがほぼ確実にメモリリークを検出してくれますし、「大丈夫なはず」のコードで、さらにツールで何も検出されなければ「確実に大丈夫」と思っていいでしょう。  
(「Xcode Leaks 使い方」あたりで検索すれば、丁寧に解説された記事がたくさん見つかります。)

ただ、100%の自身が持てないということなら、クロージャー内の`self`を弱参照にしてしまった方がいいかもしれません。  
(その場合、誰も`self`を強参照していないせいで、そのクロージャーが実行される時には`self`が解放されてしまっているという可能性も出てきてしまいます。)

[code]

    Alamofire.request(.GET, "http://hoge.com/hoge.php").validate().responseJSON { [weak self] response in
        switch response.result {
        case .Success:
            if let jsonData = response.result.value {
                let json = JSON(jsonData)
                for (_,value) in json {
                    self?.log.text = self?.log.text! + "\n" + value[1].string!.stringByRemovingPercentEncoding!
                }
            }
        case .Failure(let error):
            print(error)
        }
    }
    
[/code]

(クロージャーの最初の`[weak self]`と、`self.log`が`self?.log`になっているのに注意。)

弱参照を使うと、上に書いたようなリスクもあるので、「クロージャーではいつでも弱参照を使え」と言う言い方は暴論だと思うのですが、たいていの場合は動いてしまいますので、メモリリークを抱えたままよりはマシ、かもしれません。後はご自身でリスクをよく判断して決めてください。


CC BY-SA 3.0
2016-07-17T16:43:48.733
27691
2016-07-17T16:43:48.733
13972
27690
answer