🍁

Swiftのweakについてメモ

2020/10/28に公開

メモリリークする可能性があるパターン

class Hoge {
    var method: (() -> Void)?

    init() {
        print("Hoge init")
    }

    deinit {
        print("Hoge deinit")
    }

    func call() {
        method?()
    }
}

class Meu {
    let value: Int = 123

    init(hoge: Hoge) {
        print("Meu init")
        hoge.method = {
            print(self.value)
        }
    }

    deinit {
        print("Meu deinit")
    }
}

var hoge: Hoge! = Hoge()
var meu: Meu! = Meu(hoge: hoge)

meu = nil // => Meu deinitが出力されない
hoge.call() // => クロージャーの参照が残り、実行される
hoge = nil // => hogeのdeinitと共にクロージャーの参照がなくなり、Meu deinitが出力される
console
Hoge init
Meu init
123
Hoge deinit
Meu deinit

メモリリークしないパターン

class Hoge {
    // 中略
}

class Meu {
    let value: Int = 123

    init(hoge: Hoge) {
        print("Meu init")
	// weak selfなりunowned selfなりをつける
        hoge.method = { [weak self] in
            if let self = self {
                print(self.value)
            }
        }
    }

    deinit {
        print("Meu deinit")
    }
}

var hoge: Hoge! = Hoge()
var meu: Meu! = Meu(hoge: hoge)

meu = nil // => この時点でMeu deinitが出力される
hoge.call() // => クロージャーの参照がなくなり実行されない
hoge = nil
console
Hoge init
Meu init
Meu deinit
Hoge deinit

結論

クロージャーの中でselfとかそのクラスの変数/関数を使う時は、weak/unowned selfをつける。

Discussion