ワテのブログ

The fundamental things apply As time goes by.

2014年6月6日金曜日

[swift]Closureのunownedについて

スポンサーリンク

ClosureからselfをキャプチャするとselfとClosure間に循環参照が生じメモリが解放されないとこの辺に書いてありました。

解決策としてはClosureのキャプチャリストにunowned selfと記述しselfを保持しない形でキャプチャすればよいとのことです。

で、やってみました。

。。。解放されない気がする

import Foundation

class HTMLElement {

    let name: String
    let text: String?

    @lazy var asHTML: () -> String = {
        [unowned self] in
        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")
    }

}

func test1() {
    var paragraph:HTMLElement? = HTMLElement(name: "test1", text: "Hello, world")
    println(paragraph!.asHTML())
    paragraph = nil
}

func test2() {
    var paragraph:HTMLElement? = HTMLElement(name: "test2", text: "Hello, world")
    paragraph = nil
}

println("call: test1()")
test1()
println("call: test2()")
test2()

println("-- end --")

test2()のみdeinitのメッセージ”test2 is being deinitialized”が表示されます。
test1()はdeinitのメッセージが表示されません。

追記
weakでキャプチャするとtest1()でもdeinitがよばれます

@lazy var asHTML: () -> String = {
    [weak self] in
    if let text = self!.text {
        return "<\(self!.name)>\(text)</\(self!.name)>"
    } else {
        return "<\(self!.name) />"
    }
}

追記

stackoverflowに同様のトピックあり。 ios - Object is not deallocated when capturing by closures in Swift - Stack Overflow

追記

Xcode6-Beta3にて解放されるようになりました。

スポンサーリンク

2 件のコメント:

  1. test2()をコメントアウトしたらどうなりますか?

    返信削除
    返信
    1. コメントありがとうございます。test2()をコメントアウトして試しましたが、やはりtest1のdeinitのメッセージは表示されませんでした。

      削除