이런 에러를 만난 적이 있나요?
이 에러가 발생하는 원인은 탈출 클로저가 있어야 할 자리에 비탈출 클로저가 있어서 입니다.
탈출 클로저와 비탈출 클로저에 대해선 다음 번에 다뤄볼게요!
이 문제를 해결하기 위해 한번 오류 상황을 만들어보겠습니다!
let evenNumberPredicate = { (number: Int) -> Bool in
return number % 2 == 0
}
func countEvenNumber(in array: [Int], predicate: (Int) -> Bool) -> Int {
return array.lazy.filter { predicate($0) }.count
}
이 경우에 에러가 발생하는 이유는 lazy 컬렉션을 사용했기 때문입니다!
lazy 컬렉션은 비동기 작업을 할 때 사용되기 때문에 그 뒤에 나오는 filter 메소드는 탈출 클로저(escaping closure) 를 요구하게 됩니다.
그래서 위와 같이 탈출 클로저가 있어야 하는데 비탈출 클로저가 있잖아? 라는 오류를 만나게 되는 것이죠.
그렇다면 이를 어떻게 해결할 수 있을까요?
위 오류는 withoutActuallyEscaping(_:do:)이라는 함수를 통해 해결 할 수 있습니다.
이 함수를 통해 non-escaping closure를 escaping closure인 것 처럼 사용 할 수 있습니다.
그렇다면 위의 코드를 withoutActuallyEscaping(_:do:)를 이용하여 바꿔볼까요?
let evenNumberPredicate = { (number: Int) -> Bool in
return number % 2 == 0
}
func countEvenNumber(in array: [Int], predicate: (Int) -> Bool) -> Int {
return withoutActuallyEscaping(predicate, do: { escapablePredicate in
return array.lazy.filter { escapablePredicate($0) }.count
})
}
이렇게 withoutActuallyEscaping(_:do:) 함수의 첫번째 인자로 탈출 클로저인 척 해야하는 우리의 비탈출 클로저를 전달해주고, do에서는 비탈출 클로저를 매개변수로 받아 filter에서 작업을 실행하게 됩니다.
withoutActuallyEscaping(_:do:)를 이용하여 비탈출 클로저(non-escaping closure)를 탈출 클로저(escaping closure)처럼 사용할 수 있다!