본문 바로가기
Swift

@escaping에 관하여

by iOS 개린이 2022. 8. 25.

@escaping

 

함수를 파라미터로 받는 함수가 있다고 한다.

ex) 

func doSomething(completion : () -> ()) {

      print( "start" )

      DispatchQueue.main.asyncAfter( deadline : .now() + 10{ 
            completion() 
      }

      print( "end" )

}

이 함수는 error가 발생한다. 왜냐하면 함수의 실행흐름이 끝나고 나서 completion이 실행되기 때문이다. 이렇게 non-escaping closure 형식은 함수 내에서 모든 실행을 맞춰야 한다.

하지만 파라미터 앞에 @escaping을 붙여준다면 모든 함수가 종료되고 나서 10초 후에 completion이 실행된다. 

 

여기서 "@escaping을 붙여준다면 파라미터로 받은 함수를 함수 내의 모든 실행흐름이 끝나고 나서 실행되는 처리를 할 수 있겠구나" 라고 잘못된 생각을 했다.

fire storage에 image를 업로드하고, 그 url을 받아서 firestore에 저장하는 방식인데, @escaping을 통해 url을 받는 함수가 끝나면 다음으로 firestore에 저장하는 함수를 실행하려고 했다. 하지만 계속 파라미터로 받은 firestore에 데이터를 저장하는 함수가 먼저 실행되었다.

 

자문을 받았을 때 escaping에 대해서 잘 못 이해하고 있다고 했다.

받았던 자문들은 

-escaping 클로저는 아주 쉽게 말해서는 언제가 될지 모르는 시점을 알고싶을 때 사용한다.

-image를 업로드하는 함수가 비동기 처리로 이루어져있는 상황이기 때문에 파라미터로 받은 함수가 먼저 실행된다.

-image를 업로드하는 함수와 data저장 함수를 분리하고, Dispatch Group에 대해서 알아봐라.

 

-함수는 처음부터 끝까지 실행되는데, 이미지 업로드와 같은 네트워크 통신은 해당시점에 바로 끝나지 않고, 우리가 그 시점을 알 수도 없다. 그래서 함수 호출이 끝났는데도 작업하고 있는 것의 끝난 시점을 알기 위해서 escaping을 사용하는 것이다. 현재 completion의 위치가 잘못되었고, escaping을 쓴 이유는 없는 것과 마찬가지다. 

 

-함수 호출이 끝나는 건 모든 작업이 완료된 시점이 아니라, 함수 내의 모든 코드가 읽혔을 때 끝난것이다. 그래서 escaping은 함수의 호출이 끝났는데도 작업을 하고 있는 것들의 끝을 알기 위한 기능인 것이다. 

completion핸들러 != 함수의 모든 작업의 끝이 나면 동작한다 <- completion핸들러는 한 작업의 끝을 알려주는 것일 뿐 함수의 끝이 아니다. 

 

자문들을 아무리 읽어봐도 쏙쏙 이해는 되지 않는다. 이해한 정도를 풀어보면 함수는 호출하는 것과 네트워킹 등과 같은 작업을 하는 것과는 다르다. 그래서 내가 잘못 사용한 escaping은 함수의 호출이 모두 끝나고 사용한다고 이해한 것이고, 올바른 escaping 작업은 image 업로드 작업이 모두 완료되고 난 후에 escaping이 나오는 것이다.

 

새롭게 이해한 생각1 : 함수 내의 작업들이 존재한다. 그리고 작업들은 요청과 응답이 존재한다. escaping은 작업에 대한 요청과 응답이 모두 끝났을 때 사용되는 것이 아니라, 단지 함수 내의 모든 작업들을 실행시켰을 때 escaping이 발생된다고 생각한다. 즉, 응답이 오고 안오고를 떠나서 함수 내의 작업이 모두 요청을 보냈을 때(실행되었을 때) escaping이 발생하는 것이다. 응답시간을 알고 싶다면 completion handler를 사용하는 것이 맞다.

 

이것은 오랜시간 삽질을 해보고..혼자 고민도 많이 해본 개인적인 생각입니다. 부족한 저를 알려주실분 댓글 환영합니다!

'Swift' 카테고리의 다른 글

Protocol에 관하여  (0) 2022.11.14
lazy variables에 관하여  (0) 2022.10.07
순환참조에 관하여  (0) 2022.09.28
Class와 Struct  (0) 2022.07.04
getter와 setter 그리고 willSet과 didSet  (0) 2022.07.01