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


162

주어진:

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클로저가 함수의 범위를 벗어나 므로 올바른 것으로 보이지 않습니다 .


21
"를 제거 @escaping속성을, 코드 컴파일 및 실행"-에 설명 된대로 때문의 SR-2444 , Action?탈출, 기본적으로있다. 따라서 @escaping옵션 폐쇄를 사용할 때 제거 하면 필요한 것을 달성 할 수 있습니다.
Rob


타입 별칭 클로저가 탈출
Masih

다음 은 Ole Begemann훌륭한 기사로, 왜 발생하는지와 선택적 매개 변수를 @noescape로 설정하려는 경우 몇 가지 해결 방법을 설명합니다.
Senseful

답변:


122

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)->()>, 임의 폐쇄 탈출한다.


5
지금 받기@escaping may only be applied to parameters of function type func doStuff(stuff: String, completion: (@escaping ()->())?) {
Lescai Ionel

1
a temporary solution is remove the @escaping attribute from optional function type, that keep the function as escaping. 더 자세히 설명해 주시겠습니까? swift 3의 기본 의미는 이스케이프가 아닙니다. @escaping없이 컴파일되지만 비 탈출로 처리되어 문제가 발생할 것입니다. 그렇지 않습니까?
Pat Niemeyer

49
자세히 읽으면 SR-2444에 모든 선택적 클로저가 이스케이프 처리되는 것으로 보이며 이는 보완 버그입니다.) 수정되면 컴파일하면 변경 사항을 경고한다고 가정합니다.
Pat Niemeyer

어쩌면 약간의 주제 일 수도 있습니다. 그러나 이것은 어떻게 작동 @autoclosure합니까? 하나는 같은 오류가 발생합니다 ...
Gee.E

그것은 @escaping없이 작동합니다 __ func doStuff (stuff : String, complete : (()-> ())?) {
Феннур Мезитов

226

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

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

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


7
이것이 주제에 가장 중요한 정보를 추가한다고 생각합니다. 대답이 받아 들여 져야합니다.
Damian Dudycz

합리적인 대답. 이것이 바뀔 가능성은 얼마나됩니까?
GoldenJoe

2
기술적으로 말하는 (()->Void)?것은 당신이 가진 말과 동일 하고 소유권을 유지 Optional<()->Void>하기 위해서는 기능 Optional만을 받아 들여야하기 때문에 이것은 의미가 있습니다 @escaping. 세 번째로 이것이 정답이되어야합니다. 감사합니다.
딘 켈리

22

혼합 @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)
}

이것은 구현이 깨끗하고 예쁘다.
Fred Faust

2
이 블록이 비어 있거나 비어 있는지 확인하려면 어떻게합니까?
Vyachaslav Gerchicov

2
Bummer, 프로토콜 방식으로는 작동하지 않습니다. "프로토콜 방법에서는 기본 인수를 사용할 수 없습니다"(Xcode 8.3.2).
Mike Taverne

17

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

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

4

예제에서 이해해야 할 중요한 사항 은 클로저 변경 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
        }
    }
}

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.