2017-02-13 5 views
8

한 탈출을 허용 할 수 있습니다스위프트 3 : 여기</p> <pre><code>Closure use of non-escaping parameter may allow it to escape </code></pre> <p>내 코드는 다음과 같습니다 : 비 탈출 매개 변수의 폐쇄 사용은 내가하지만이 오류가 발생하고있어 내가 완료 핸들러를 다음과 같은 기능

func makeRequestcompletion(completion:(_ response:Data, _ error:NSError)->Void) { 
    let urlString = URL(string: "http://someUrl.com") 
    if let url = urlString { 
     let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, urlRequestResponse, error) in 
      completion(data, error) // <-- here is I'm getting the error 
     }) 
    task.resume() 
    } 
} 

enter image description here 왜이 오류가 발생하는지 알고 계십니까?

난 정말 당신이 명시 적으로 폐쇄가 탈출 할 수 있는지 정의 할 필요가 같은

+0

[탈출하지 못하는 매개 변수의 클로저를 사용하면 탈출 할 수 있습니다.] (https://stackoverflow.com/q/38990882/6521116) –

답변

8

이 보이는 도움을 주셔서 감사합니다. Apple Developer docs 가입일

,

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.

TLDR; 완료 변수 후 @escaping 키워드를 추가

func makeRequestcompletion(completion: @escaping (_ response:Data, _ error:NSError)->Void) { 
    let urlString = URL(string: "http://someUrl.com") 
    if let url = urlString { 
     let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, urlRequestResponse, error) in 
      completion(data, error) // <-- here is I'm getting the error 
     }) 
     task.resume() 
    } 
} 
+0

@escaping을 요청하는 이유는 무엇입니까? – user2924482

+3

이제 Swift 3에서는 함수가 호출 된 후 실행되는 완료 핸들러 (escaping)가 함수에 언제 포함되어야하는지 명시 적으로 정의해야합니다. 애플은 "함수가 연산을 시작한 후에 리턴한다.하지만 연산이 완료 될 때까지 클로저가 호출되지 않는다. 클로저는 나중에 호출해야한다. ...이 매개 변수를 표시하지 않았다면 함수를 @escaping으로 사용하면 컴파일 타임 오류가 발생합니다. " –

+0

@MarkBarrasso에게 감사의 말을 전하러 간다. 독서했지만 couln't는 전체 "탈출"일을 이해하고,이 의견은 내가 빛을 볼 수있게했다;) –

3

에 "탈출"폐쇄가 만들어 졌는지 범위를 오래 살 수있는 폐쇄입니다 이스케이프 폐쇄는 참조 카운팅 및 메모리 관리 주위에 특별한주의를 필요로하고 더 열심히 할 수 있습니다. 최적화 할 수 있습니다.

스위프트 3 이전에는 클로저의 기본값은 이스케이프 중임을 가정합니다. 이는 개발자가 컴파일러가 최적화를 할 수 있도록 이 아닌이 아닌 클로저를 명확하게 식별해야한다는 것을 의미했습니다. 커뮤니티는 실제로 컴파일러가 클로저가 이탈하는지 여부를 쉽게 알 수 있으며 탈출에 대한 공격적인 접근이 더 빠른 코드를 초래할 수 있다고 판단했습니다. 결과적으로 클로저가 비 - 이스케이프 처리로 간주되므로 @escaping 특성으로 이스케이프중인 클로저에 플래그를 지정해야합니다.

귀하의 경우, URLSession.shared.dataTask이 받아들이는 폐쇄는 그 자체로 도주 형 폐쇄이므로 내부에 폐쇄 형을 사용하는 경우에는 @escaping으로 표시해야합니다.

+0

수정 방법에 대한 코드 예제는 훌륭합니다. – Linasses

+0

@Linasses'completion : @escaping (_ response : Data, _ error : NSError) -> Void'. – zneak

+1

이미'@ 이스케이프 처리 '를하고 있지만'@ 이스케이프 처리 중'오류가 발생합니다 : | | open func resumeSession (_ 완료 : @escaping (결과 ) -> (Void)) {@ 이미 이스케이프 처리를하고 있지만 이스케이프 오류 팝업이 표시됩니다. @expaping (Result ) -> (Void)) { –

0

@escaping은 모든 호출 메소드에 감염되며 이 포함되어야하는지 컴파일러에서 결정합니다.

(컴파일 된)이 예를 고려

dispatchSometime({ print("Oh yeah") }) 

func dispatchSometime(_ block:()->()) { 
    dispatchNow(block) 
} 

func dispatchNow(_ block:()->()) { 
    block() 
} 

이 변형 예는, 그러나, 유형 non-escaping parameter may allow it to escape 에러를 생성한다 :

dispatchSometime({ print("Oh yeah") }) 

func dispatchSometime(_ block:()->()) { 
    dispatchLater(block) 
} 

func dispatchLater(_ block:()->()) { 
    DispatchQueue.main.async(execute: block) 
} 

메인 디스패치가 dispatchLater 방법 요구 수단 @escaping을 추가했으면 dispatchSometime 방법 에가 필요합니다. 컴파일 할 예제는을 참조하십시오.

dispatchSometime({ print("Oh yeah") }) 

func dispatchSometime(_ block: @escaping()->()) { 
    dispatchLater(block) 
} 

func dispatchLater(_ block: @escaping()->()) { 
    DispatchQueue.main.async(execute: block) 
} 

그러나 빼앗아 단지입니다 :

  • 보관할 컴파일러가 불평을 멈출 때까지 호출 체인까지 @escaping를 추가.
  • 키워드는 아무 것도 바뀌지 않습니다. 즉, 기본적으로 "차단 된 변수가 블록 자체와 함께 유지 될 수 있으므로 weak을 사용하도록주의하십시오."라는 경고입니다. 당신이 불평을 막을 수있는 컴파일러를 얻는 @escaping 키워드를 포함하는 여러 가지 방법을 조정해야 할 경우

의미

이 가진 정말 재미 경우입니다. 그러나 해당 메소드가 실제로 프로토콜을 준수하는 경우 해당 프로토콜의 메소드는 @escaping 키워드를 가져와야하며 다른 모든 프로토콜 준수 프로토콜에도 감염됩니다. 장난!