Moon Work

[Swift] @escaping 키워드와 클로저 본문

Swift

[Swift] @escaping 키워드와 클로저

moonkey 2023. 3. 11. 15:10

시작하며

javascript라는 법이 없는 나라에서 온 나는 Swift의 @escape 키워드가 당황스럽고 또 놀랍다. @escape는 클로저를 인자로 전달받는 함수 내부에서 외부로 클로저를 전달하는 경우(비동기 등으로 클로저를 전달 받았을 때) 사용하는 키워드이다. 어떤 경우에 사용하는지 알아보자.

 

escaping-closure and non-escaping-closure

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.

escaping-closure는 인자로 전달받는 closure를 함수 외부에 할당하거나 함수가 종료된 이후에 사용하는 경우에 사용한다. 기본적으로 클로저는 non-escaping 클로저이기 때문에 다른 함수에 인자로 전달해주거나 클로적를 저장해 두고 사용하기 위해서는 closure를 받는 인자 앞에 @escaping 키워드를 붙여주어야 한다.

class Weather {
	var completion : (() -> Void)?
    
	func getWeather(completionHandler: @escaping () -> Void){
    	completion = completionHandler
    }
}

 

escaping-closure와 weak self

closure는 context capture를 통해 클래스의 인스턴스를 참조한다. 따라서 @escaping 을 통한 클로저에 인자로 클로저를 보내는 경우 순환 참조(ARC)를 통한 메모리 누수가 발생할 가능성이 있다. 

위와 같은 순환참조를 막기 위해 [weak self]를 통해 인스턴스에 대한 약한 참조를 함으로 순환참조를 대비할 수 있다. 예시를 통해 확인해보자. 

final class WeatherManager {   
    static let shared = WeatherManager()
    private init() {}
    
    typealias NetworkCompletion = (Result<WeatherData, NetworkError>) -> Void
    //⭐️ @escaping으로 다른 함수로 전달 가능한 escaping-closure로 변환
    func getWeatherInfo(completion: @escaping NetworkCompletion){
        let urlString = "\(WeatherAPI.requestURL)\(WeatherAPI.params)&appid=\(SecretKey.apiKey)"
        performRequest(urlString: urlString,completion: completion)
    }
    ...
 }
 ...
 func setupData(){
 		var weatherInfo: String?
        //⭐️ weak self ⭐️를 통한 약한 참조
        weatherManager.getWeatherInfo { [weak self] result in
            switch result {
            case .success(let weatherData):
                self?.weatherInfo = weatherData.weather[0].main
            case .failure(let error):
                print(error.localizedDescription)
            }
        }
    }

getWeatherInfo라는 함수를 통해 클로저를 전달하는데 weak self 키워드를 통해 약한 참조를 통해 보내고 @escaping 키워드를 통해 받은 클로저를 다른 함수의 인자로 다시 보낼 수 있게 할 수 있었다.

 

 

 

 

References

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/

 

Documentation

 

docs.swift.org

https://velog.io/@parkgyurim/Swift-escaping-closure

 

[Swift] @escaping 클로저

📚 Swift @escaping 클로저에 대해 알아보자

velog.io