본문 바로가기
iOS/Swift

Swift) non-Escaping Closure vs Escaping Closure

by Jiseong 2022. 2. 20.

non-Escaping Closure vs Escaping Closure

Swift에서 함수와 클로저는 일급 객체이다. 

 

일급 객체라 함은 함수에 파라미터로 전달하고, 함수의 반환값이 될 수 있으며, 변수, 상수에 저장을 할수 있는 것을 의미한다.

non-Escaping Closure의 경우 클로저가 함수 본문을 탈출하지 않는다. 

 

함수가 종료되기 전에 클로저가 실행된다는 것이다.

 

방금 위에서 말한 두 줄이 non-Escaping Closure와 Escaping Closure의 가장 큰 차이점이라는 것을 알아야 한다

그림으로도 대강 설명이 되있지만 흐름을 단계별로 써보자면..

  1. 함수 호출
  2. 클로저가 nonEscapeSquare 파라미터(completion)로 들어감
  3. 함수 내부에서 completion 실행
  4. completion이 값 반환하고 함수 종료

클로저가 함수가 종료되기 전에 호출이 되어 실행되는 것을 볼 수 있다.

 

그럼 뭘까??? nonEscapeClosure 인거임

 

더 확실한 차이를 알기위해서 하나 더 설명을 하자면!!

 

비동기에서 nonEscapeClosure를 실행할 경우를 보자..

비동기에서 nonEscapeClosure가 안되는 이유는 해당 클로저가 담긴 completion이 비동기로 실행되기때문에 종료 시점을 알 수가 없다. 

 

전에도 알아봤지만 비동기는 그냥 DispatchQueue에 던져버리고 신경안쓴다고 그랬었다!! 그냥 일 처리 되든 말든 함수 종료 시킨다고..

 

비동기로 실행되는 nonEscapeClosure가 함수가 종료되고 실행이되므로 nonEscapeClosure는 함수 외부에서!! 함수가 종료되면!!!! 사용될 수 없다고 Escape로 바꾸라고 컴파일 오류가 뜨는 것이다

.

이제 확실히 알겠지..?

 

nonEscapeClosure는 함수 외부에서 사용 할 수 없!!!!다!!!!!!!!!

 

또한 메모리 관점에서도 설명할 것이 있는데..

 

nonEscapeClosure의 경우 함수의 호출과 종료에 따라 동일하게 실행되고 종료된다.

 

만일 클로저 내부에서 외부 상수나 변수를 참조한다면.. 참조할때 retainCount + 1, 함수가 종료되면서 -1 되므로 RC 문제가 없다.

class Test {
    init() {
        print(#function)
    }
    
    var testNum = 1
    
    deinit {
        print(#function)
    }
}

func nonEscapeSquare(number: Int, comletion: (Int) -> ()) {
    let resultNumber = number * number
    comletion(resultNumber)
}

nonEscapeSquare(number: 3) { number in
    let test = Test()
    test.testNum += number
    print(number)
    print(test.testNum)
}

.. 네

 

위에서 escapeClosure까지 설명된 것 같긴한데 함더 살펴보자

위처럼 탈출 클로저로 만들게되면 해당 클로저를 외부 변수,상수에 저장할 수 있다.

 

그리고 클로저를 가진 함수가 종료되어도 클로저 실행이 가능하다. 외부에 저장하고 나중에 쓸 수 있으니깐 당연히 함수가 종료되어도 쓸수 있어야겠지?

 

위 이유가 가장 큰 차이이다.

 

대표적으로 escapeClosure가 사용되는 URLSession이다.

func makeRequest(_ completion: @escaping (Result<(Data, URLResponse), Error>) -> Void) {
  URLSession.shared.dataTask(with: URL(string: "http://a.jollida/")!) { data, response, error in
    if let error = error {
      completion(.failure(error))
    } else if let data = data, let response = response {
      completion(.success((data, response)))
    }
  }
}

위 코드는 순서가 어떻게 될까?

dataTask의 클로저는 비동기로 네트워크 요청을 보내 응답이 오면 dataTask의 completion 함수가 호출되고, 내부에서 조건에 따라 makeRequest의 completion을 호출 하는 것이다.

 

더 설명을 못하겠다.

 

이게 다인 것 같아서.. 조만간 캡쳐나.. 탈출 클로저의 참조부분을 써봐야겠다.

'iOS > Swift' 카테고리의 다른 글

Swift) final  (0) 2022.02.20
Swift) Frame vs Bounds  (0) 2022.02.20
Swift) Unit Test without networking  (0) 2022.02.20
Swift) GCD (Grand Central Dispatch)  (0) 2022.02.15
Swift) Main.sync 외 않됌?  (1) 2022.02.13

댓글