[iOS]Escaping Closure(@escaping)

@escaping 📑

About @escaping ▾

escaping을 접하다 ▾

func fetchUser(completion: @escaping(User) -> Void) {
	...
}
  • 위의 코드처럼 통신이나 비동기 처리를 할 때 이러한 코드를 본 적이 있습니다.
  • completion 클로저를 파라미터로 작성하면서 @escaping이 붙은 걸 보면서 어떨 때 사용하는지 느낌만 알고, 정확히 어떨 때 사용하며 무엇인지 몰랐습니다.

 

정의 ▾

  • Escaping Closure
    • 클로저가 함수의 인자로 전달됐을 때, 함수의 실행이 종료된 후 실행되는 클로저입니다.
  • Non-Escaping Closure
    • 함수의 실행이 종료되기 전에 실행되는 클로저입니다.

 

비교하기 ▾

  • Non-Escaping Closure
func fetchUser(completion: () -> Void) {
	completion()
}
  • 실행 순서 ▾
    1. 클로저가 fetchUser() 함수의 completion 인자로 전달됩니다.
    2. 함수 안에서 completion() 이 실행됩니다.
    3. fetchUser() 함수가 값을 반환하며 종료가 됩니다.

 

  • Escaping Closure
class UserViewModel {
	var completionHandler: (() -> Void)? = nil
    
    func fetchUser(completion: @escaping () -> Void) {
    	completionHandler = completion
    }
}
  • 실행 순서 ▾
    1. 클로저가 fetchUser() 함수의 completion 인자로 전달이 됩니다.
    2. 클로저 completion이 completionHandler 변수에 저장이 됩니다.
    3. fetchUser() 함수가 값을 반환하고 종료됩니다.
    4. 클로저 completion은 아직 실행되지 않은 상태입니다.
  • completion은 함수의 실행이 종료되기 전에 실행되지 않기 때문에 escaping closure(함수 밖)에서 실행되는 클로저입니다.

 

의문점 🤷🏻‍♂️

  • Non-Escaping Closure에서도 @escaping이 붙어 있을 수 있는데, 모든 클로저 파라미터 타입에 @escaping을 붙여서 사용해도 되지 않을까?

 

의문에 대한 해답 📂

  • 우선 나누어져 있는 이유를 알면 편합니다. ▾
    • 컴파일러의 퍼포먼스의 최적화로 인해 나누어 사용을 한다.(Escaping Closure && Non-Escaping Closure)
      • Non-Escaping Closure는 컴파일러가 클로저의 실행이 언제 종료되는지 알기 때문에, 때에 따라 클로저에서 사용하는 특정 객체에 대한 retain, release 등의 처리를 생략해 객체의 생명주기를 효율적으로 관리할 수 있습니다.
      • Escaping Closure는 함수 밖에서 실행되기 때문에 클로저가 함수 밖에서도 적절히 실행되는 것을 보장하기 위해, 클로저에서 사용하는 객체에 대한 추가적인 참조 사이클 관리 등을 해줘야 합니다.
      • 위의 부분에서 컴파일러의 퍼포먼스의 최적화에 영향을 끼치기 때문에 Swift에서는 필요에 따라 escaping closure를 사용하도록 구분해 두었습니다.

 

Escaping 이점 ▾

  • 해당 클로저를 외부 변수/상수에 저장이 가능해집니다.
  • 해당 함수가 끝나서 리턴된 이후에도 클로저 실행이 가능합니다.

 

그래서 왜 사용하는 건데??

예시 코드 ▾

func setImage(url: String) -> UIImage {
	var image = UIImage()
    
    Alamofire.request(url).responseImage { (response) in
    	if let image = response.result.value {
        	data = image
        }
    }
    return data
}

 

예시 설명 ▾

  • Alamofire.request는 비동기적으로 실행시킬 때, Alamofire의 완료 여부와 상관없이 따로 return data가 실행이 됩니다.
  • return data가 실행되기 이전에 서버에서 이미지를 받아오는 부분이 안 끝나면 nil이 return이 됩니다.

  • 이럴 때 @escaping closure를 사용하면 됩니다.
  • 함수가 반환이 돼도 나중에 서버 작업 완료될 때 전달받는 것이 가능해집니다.
  • 데이터를 수신에 대한 안전이 보장되는 형태가 형성이 됩니다.

'iOS_Swift.zip' 카테고리의 다른 글

[iOS]lazy 키워드  (0) 2022.02.16
[iOS]Frame과 Bounds의 차이  (0) 2022.02.14
[iOS]SDWebImage 에러  (0) 2022.02.11
[iOS]카카오 로그인(소셜)  (0) 2022.01.25
[iOS]면접 정리(1)  (1) 2022.01.20