Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swiftでなんで[weak self]するのか?

oyuk
April 05, 2018
3.5k

Swiftでなんで[weak self]するのか?

oyuk

April 05, 2018
Tweet

Transcript

  1. Swiftでなんで[weak self]するのか?
    2018/03/30
    oyuk(@oydku)
    1

    View Slide

  2. 自己紹介
    oyuk(@oydku)
    プログラマ
    2

    View Slide

  3. weak selfについて
    よくあるアレ
    { [weak self] event in
    guard let strongSelf = self else { return }
    //
    なんかする
    }
    3

    View Slide

  4. 結論から
    [weak self]
    と書くことでクロージャが self
    を弱参照し、クロージャと self
    の循環参照を防ぐ
    4

    View Slide

  5. は?
    [weak self]
    ってなんじゃその書き方は
    弱参照?循環参照?
    5

    View Slide

  6. [weak self]
    ってそんな書き方ありなん?
    今回の本質じゃないから軽く
    「 [weak self]
    と書くことでクロージャが self
    を弱参照する」これだけ覚えておいて
    ちなみに [weak self]
    はキャプチャリストと呼ぶ
    6

    View Slide

  7. 弱参照?循環参照?
    参照カウントというGCの概念
    これを理解するために
    参照カウントについて
    Swiftの参照カウント(Automatic Reference Counting)について少し
    7

    View Slide

  8. 参照カウント
    GCの一種
    オブジェクトに対して参照している他のオブジェクトの数を記憶する(参照カウント)
    1以上なら生きている。メモリに割り当てられている
    0になると死。解放される
    8

    View Slide

  9. 参照カウント
    例1
    class Hoge {}
    // Hoge
    のインスタンスの参照カウントが1
    になる
    var h: Hoge? = Hoge()
    9

    View Slide

  10. 参照カウント
    例2
    class Hoge {}
    // Hoge
    のインスタンスの参照カウントが1
    になる
    var h: Hoge? = Hoge()
    // Hoge
    のインスタンスの参照カウントが0
    になり解放される
    h = nil
    10

    View Slide

  11. 参照カウント
    例3
    class Hoge {
    var fuga: Fuga?
    }
    class Fuga {
    var hoge: Hoge?
    }
    var hoge: Hoge? = Hoge() // hoge
    の参照カウント1
    var fuga: Fuga? = Fuga() // fuga
    の参照カウント1
    hoge.fuga = fuga // hoge
    の参照カウント2
    fuga.hoge = hoge // fuga
    の参照カウント2
    hoge = nil // hoge
    の参照カウント1
    fuga = nil // fuga
    の参照カウント1
    hoge
    も fuga
    も参照することができないのにメモリ上に残ったままになっている
    hoge
    と fugga
    で循環参照が起きている 11

    View Slide

  12. 参照カウント
    例4
    class Hoge {
    private var closure: (() -> Void)?
    private var count = 0
    init() {
    closure = createClosure()
    }
    func createClosure() -> (()-> Void) {
    return {
    self.count += 1
    }
    }
    }
    var h: Hoge? = Hoge() // Hoge
    の参照カウント2 , closure
    の参照カウント1
    h = nil // Hoge
    の参照カウント1
    hoge
    と closure
    で循環参照が起きている 12

    View Slide

  13. 循環参照
    var h: Hoge? = Hoge() // Hoge
    の参照カウント2 , closure
    の参照カウント1
    h = nil // Hoge
    の参照カウント1
    13

    View Slide

  14. 循環参照解決策
    class Hoge {
    private var closure: (() -> Void)?
    private var count = 0
    init() {
    closure = createClosure()
    }
    func createClosure() -> (()-> Void) {
    return { [weak self] in
    self?.count += 1
    }
    }
    }
    var h: Hoge? = Hoge() // Hoge
    の参照カウント1 , closure
    の参照カウント1
    h = nil // Hoge
    の参照カウント0
    解放される! 14

    View Slide

  15. なぜ
    func createClosure() -> (()-> Void) {
    return { [weak self] in
    self?.count += 1
    }
    }
    [weak self]
    は self
    を参照するが参照カウントは+1しないという意味
    これが弱参照
    ちなみに今までのは強参照
    循環参照が起こらなくなる
    15

    View Slide

  16. なぜ
    var h: Hoge? = Hoge() // Hoge
    の参照カウント1 , closure
    の参照カウント1
    h = nil // Hoge
    の参照カウント0
    16

    View Slide

  17. なぜ
    hは参照カウントは0なので解放される
    closureも参照カウント0なので解放される
    17

    View Slide

  18. まとめ
    { [weak self] event in
    guard let strongSelf = self else { return }
    //
    なんかする
    }
    [weak self]
    と書くことでクロージャが self
    を弱参照し、クロージャと self
    の循環参照を
    防ぐ
    18

    View Slide

  19. 19

    View Slide