[swift] 스위프트 선택적 이스케이프 폐쇄 매개 변수

주어진:

typealias Action = () -> ()

var action: Action = { }

func doStuff(stuff: String, completion: @escaping Action) {
    print(stuff)
    action = completion
    completion()
}

func doStuffAgain() {
    print("again")
    action()
}

doStuff(stuff: "do stuff") { 
    print("swift 3!")
}

doStuffAgain()

유형 의 completion매개 변수 (및 action) 를 만들고 Action?유지하는 방법이 @escaping있습니까?

유형을 변경하면 다음 오류가 발생합니다.

@escaping 속성은 함수 유형에만 적용됩니다

@escaping속성을 제거하면 코드가 컴파일되고 실행되지만 completion클로저가 함수의 범위를 벗어나 므로 올바른 것으로 보이지 않습니다 .



답변

SR-2552 보고 @escaping기능 유형 별칭을 인식하지됩니다. 그래서 오류 @escaping attribute only applies to function types입니다. 함수 시그니처에서 함수 유형을 확장하여 임시 해결책을 찾을 수 있습니다.

typealias Action = () -> ()

var action: Action? = { }

func doStuff(stuff: String, completion: (@escaping ()->())?) {
    print(stuff)
    action = completion
    completion?()
}

func doStuffAgain() {
    print("again")
    action?()
}

doStuff(stuff: "do stuff") {
    print("swift 3!")
}

doStuffAgain()

편집 1 : :

실제로 버그 SR-2552 가 아직 해결되지 않은 xcode 8 베타 버전을 사용하고 있었습니다. 그 버그를 수정하고 여전히 열려있는 새로운 버그 (당신이 직면하고있는 버그)를 소개했습니다. SR-2444를 참조하십시오 .

임시 해결책으로 @Michael Ilseman이 지적한 해결 방법 은 함수를 escaping으로 유지하는@escaping 선택적 함수 유형에서 속성을 제거하는 것입니다 .

func doStuff(stuff: String, completion: Action?) {...}

편집 2 : :

SR-2444은 매개 변수의 위치에 폐쇄가 있음을 명시 적으로 진술 폐쇄되어 있지 탈출하고 표시 할 필요할 @escaping선택적 매개 변수 그들을 탈출하기 위해,하지만 되어 있기 때문에, 암시 탈출 ((Int)->())?의 동의어이며 Optional<(Int)->()>, 임의 폐쇄 탈출한다.


답변

보낸 사람 : swift-users 메일 링리스트

기본적으로 @escaping은 함수 매개 변수 위치의 클로저에서만 유효합니다. 기본적으로 noescape 규칙은 함수 매개 변수 위치에서 이러한 클로저에만 적용되며, 그렇지 않으면 이스케이프됩니다. 값이 연관된 열거 형 (예 : 선택 사항), 튜플, 구조체 등의 집계와 같이 집계가있는 집계는 함수 매개 변수 위치에 있지 않은 (즉, 탈출하는) 클로저에 대한 기본 규칙을 따릅니다.

따라서 선택적 함수 매개 변수는 기본적으로 @escaping입니다.
@noeascape는 기본적으로 함수 매개 변수에만 적용됩니다.


답변

혼합 @escaping과 비가 @escaping혼동 되기 때문에 비슷한 문제가 발생했습니다 . 특히 클로저를 통과 해야하는 경우 특히 그렇습니다.

나는 via 매개 ​​변수에 no-op 기본값을 지정하여 via를 통해 종료했습니다 = { _ in }.

func doStuff(stuff: String = "do stuff",
        completion: @escaping (_ some: String) -> Void = { _ in }) {
     completion(stuff)
}

doStuff(stuff: "bla") {
    stuff in
    print(stuff)
}

doStuff() {
    stuff in
    print(stuff)
}


답변

이 방법으로 경고없이 Swift 3에서 작동하게했습니다.

func doStuff(stuff: String, completion: (()->())? ) {
    print(stuff)
    action = completion
    completion?()
}


답변

예제에서 이해해야 할 중요한 사항 은 클로저 변경 Action하면 탈출하는 것입니다. 제안하는 것을 해보자.Action?

typealias Action = () -> ()

var action: Action? = { }

func doStuff(stuff: String, completion: Action?) {
    print(stuff)
    action = completion
    completion?()
}

자 이제 전화하겠습니다 doStuff.

class ViewController: UIViewController {
    var prop = ""
    override func viewDidLoad() {
        super.viewDidLoad()
        doStuff(stuff: "do stuff") {
            print("swift 3!")
            print(prop) // error: Reference to property 'prop' in closure
                        // requires explicit 'self.' to make capture semantics explicit
        }
    }
}

글쎄, 그 요구 사항은 폐쇄를 탈출하는 경우에만 발생합니다. 따라서 폐쇄는 탈출하고 있습니다. 따라서 이스케이프 표시 하지 않는 이유는 이미 이스케이프 처리 중입니다.


답변