본문 바로가기

iOS

[Swift 문법] Optional type Closure와 @escaping

✳️ 발단

[Swift] Escaping Closure(탈출 클로저)

@escaping을 붙이지 않으면 스코프 밖의 변수인 클로저에 파라미터로 전달받은 클로저를 할당 불가능하다고 알고 있었는데 아래와 같은 코드가 잘 기능하는 것을 발견했다. @escaping을 붙이지 않았는데 어떻게 할당이 되었을까요? (탈출 클로저에 대한 설명은 위 티스토리 참조 ^__^)

private var leftButtonClosure: (() -> Void)?

@discardableResult
func leftButonAction(_ clousure: (() -> Void)? = nil) -> Self {
   self.leftButtonClosure = clousure
   self.leftButton.addTarget(self, action: #selector(leftButtonSelector), for: .touchUpInside)

   return self
}
// shout out to Gyuios!

여러 번의 시행착오을 통해 클로저 매개변수를 optional로 선언하면 탈출 가능해진다는 사실을 알게 되었고!

이것이 가능한 이유를 알기 위해 googling의 세계로 떠났습니다...

✳️ History 분석

1. @escaping 키워드는 언제부터 생겼나?

https://brunch.co.kr/@tilltue/52

위 링크에는, swift 3으로 업데이트되면서 메모리 안정성을 위하여 클로저 매개변수는 기본적으로 함수 스코프 내에서 실행되도록 escape에서 non-escape으로 바뀌었고 필요한 경우에만 @escaping을 통해서 탈출시킬 수 있도록 하는 기능을 제공했다는 내용이 담겨 있습니다!

2. @escaping에 대한 다면적인 실험

https://bugs.swift.org/browse/SR-2444?focusedCommentId=17861&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-17861

위 링크를 보시면 오직 함수 타입에만@escaping을 붙일 수 있다고 나옵니다. Xcode에서도 클로저 타입이 아닌 자료형에 @escaping을 붙이면 실제로 에러가 뜨고 있어요~!

이러한 에러가 뜨는 [클로저 타입이 아닌 자료형]에는, optional로 선언한 클로저도 포함이 되어 있었습니다.

optional 클로저에 @escaping을 붙일 수 없다 ⇒ optional 클로저는 클로저 타입이 아니라 옵셔널 타입이다 ⇒ 옵셔널 타입은 클로저 타입이 아니기에 non-escape 원칙을 적용받지 않는다 ⇒ optional 클로저는 다른 타입 인자와 같이 외부로 탈출이 가능하다

✳️ 정리

  • 스위프트에서 안정성을 위해서 함수 파라미터로 전달되는 클로저들은 기본적으로 탈출 불가하게 만들어 놓음(이유는 ARC로 인한 참조 문제 해결을 위해)
  • 그래도 탈출시키고 싶은 클로저가 있으면 @escaping을 통해서 탈출할 수 있는 기능을 만들어줌
  • 그런데 이러한 @escaping의 정의를 보면, 클로저 형식 앞에만 붙일 수 있다고 함
  • 옵셔널 클로저에 @escaping을 붙여 보니, 클로저 형식이 아니라는 에러가 뜸
  • 클로저를 옵셔널로 선언하면 클로저 타입이 아니라 옵셔널 타입이 됨
  • 옵셔널 클로저는 클로저 타입이 아니라 옵셔널 타입이기 때문에 다른 타입과 같이 탈출도 가능하게 됨

📚 마무리 : 옵셔널 타입 클로저는 클로저 형식이 아니라 옵셔널 형식으로 취급받기 때문에, 1번에서 적은 클로저의 non-escape 규칙을 적용받지 않는다. 따라서 탈출 가능하다.

Reference

옵셔널 타입 클로저 매개변수 파고들기