(discord/swift/2018/03/13/0) inout atributeの挙動について

概要

  • discord ios dev
    • #swift
    • 2018/03/13
  • inout atributeの挙動について

log

koher - 2018/03/13

最近、 inout 的に @escapingクロージャ式の中からアクセスできないようにするけど、特に out したいわけじゃないというのを表せるものがあればいいんじゃないかという気がしてるですがどうでしょう

↓の asyncAfterクロージャ式から p にアクセスするのを防ぎたい。

import Foundation

func foo() {
    let a = [2, 3, 5]
    a.withUnsafeBufferPointer { p in
        DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(3)) {
            print(p[0])
        }
    }
}

foo()
Thread.sleep(forTimeInterval: 5)

0


omochimetaru - 2018/03/13

エスケープさせたくないってことですか?


koher - 2018/03/13

↑だと a が解放された後にそのバッファのポインタ p にアクセスしちゃってるよね?


omochimetaru - 2018/03/13

そうですね、これはだめ


koher - 2018/03/13

↓だと inout だからコンパイルエラーになる。

import Foundation

func foo() {
    var a = [2, 3, 5]
    a.withUnsafeMutableBufferPointer { p in
        DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(3)) {
            print(p[0])
        }
    }
}

foo()
Thread.sleep(forTimeInterval: 5)

'escaping closures can only capture inout parameters explicitly by value'

closure_implicit_capture_without_noescape <- (DiagnosticSema.def)


omochimetaru - 2018/03/13

あ〜、なるほど、inout的にってそういう意味か。


koher - 2018/03/13

withUnsafeBufferPointerクロージャに渡される引数がそのクロージャ式のスコープの中でのみ有効なのに、せっかく @escaping を区別してるのにコンパイラがそれを強制する術がない。


omochimetaru - 2018/03/13

え、もう一個のケースでも、pはinoutじゃないのでは?

普通の引数で型がUnsafeMutableBufferPointerですよね


koher - 2018/03/13

それが inout なんですよ。意味わかんないんだけど。

あれ?違う??


omochimetaru - 2018/03/13

public mutating func withUnsafeMutableBufferPointer<R>(_ body: (inout UnsafeMutableBufferPointer<Array.Element>) throws -> R) rethrows -> R

ほんとだ、あれ?なにこれ。


koher - 2018/03/13

いや、あってた。

withUnsafeMutableBufferPointer(_:) - Array | Apple Developer Documentation

なんで inout なのかもよくわかんないんだけど、とりあえずそれのおかげで↑の asyncAfter に渡すのはコンパイラが防いでくれる。

で、この inoutout の除いたようなものがほしいなぁと。

あと、↓みたいなのも防げるかと。

fooAsync { [weak self] in
    guard let zelf = self else { return }
    zelf.foo(...)
    barAsync { [weak zelf] in // ←この [weak zelf] を忘れないようにしたい
        guard let zelf = zelf else { return }
        zelf.bar(...)
    }
}

rintaro - 2018/03/13

クラッシャー

func after(_ fn: @escaping () -> Void) {}
func with(_ fn: (inout Int) -> Void ) {}

func test() {
  with { p in
    after { [p] in
    }
  }
}

koher - 2018/03/13

@rintaro それは明示的だから仕方ないですw

明示的にしかできなくできたらいいかなと。