비동기 처리를 하던중, 네트워킹을 한 코드에서 completion이 나면, 이후에 실행될 코드를 작성을 해야하는데, 이를 코드 내부에 처리를 해주려고 하니 컴파일 에러가 발생하였다.
또한 내부에서 해당 부분을 처리해주려고 해도 코드가 더러워지는 문제를 발생시키는것같아서 escaping closure에 대해서 정리하고 해당 부분을 사용해 문제를 해결해 보고자 한다.
Closure
우선 당연하게도 closure이 뭔지 알아야 한다.
closure은 이름이 없는 함수이다.
그렇다면 이름이 있는 closure는? 함수이다.
클로저는 중요한것은 클로저 그 자체가 1급 객체이므로, 매개변수로, 반환값으로, 비교 대상으로 다 지정이 가능하다.
func getPrint() {
print("printed")
}
func getClosure(completion: ()->()) {
completion()
}
var someClosure: ()->() = getPrint
getClosure(completion: someClosure)
//printed
Trailing Closure
중요한점은 후행 클로저는 함수의 마지막 전달 인자일때 이름을 생략한 후 함수 소괄호 외부에 구현이 가능한것.
즉 기존의 swiftui 의 modifier와 같은 것이 다 후행 클로져로 되어있는 듯
View.background()
.frame()
.opacity()
이게 머냐면
View를 .background()라는 클로저를 통해서 return View, 그다음 다시 frame이라는 클로저를 통해서 return View, 그다음 opacity라는 클로저를 통해서 return View된 최종 View가 반환되는 형태인 것이다.
Non-Escaping Closure
함수 내부에서 직접 실행하기 위해서만 사용한다
따라서 파라미터로 받은 클로저는 변수나 상수에 대입할 수 없고,
중첩 함수 내부에서 클로저를 사용할 경우, 중첩함수를 리턴할 수 없다
함수의 실행 흐름을 탈출하지 않아, 함수가 종료되기 전에 무조건 실행 되어야 한다
이게 무슨말이냐 하면, 결국 우리가 쓰는 함수 안에 함수를 구현하게 되면, 함수 내부에서만 사용가능하며, 함수의흐름을 탈출할수 없다는 것이다.
Escaping closure
escaping closure는 함수가 실행흐름을 탈출해서 종료되고도 사용될수 있는, 함수를 의미한다.
이말은 메모리에서 해당 클로저는 다른 메모리에 존재하고 있으며, 해당 클로저를 불렀을때 참조하게 된다는 의미이기도 하다.
따라서 여기에서 이전의 ARC로인한, 강한 참조를 통해 생기는 메모리 누수를 막기 위해서 weak self 키워드를 통해서 순환참조를 방지 해줘야한다.
그래서 다음과 같은 코드가 가능하다.
func getPrint() {
print("printed")
}
func getClosure(completion: @escaping ()->())->() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
completion()
}
}
var somePrint: ()->() = getPrint
var someClosure: (@escaping ()->())->() = getClosure
someClosure {
somePrint()
}
// printed
웃긴게 뒤에 ()를 붙이는 순간 함수가 호출된다.
함수명을 변수에 담을때는 ()를 포함하지 않아야한다.
Uploaded by N2T