#1
func downloadJson(_ url:String, _ completion: @escaping (String?) -> Void ) {
DispatchQueue.global().async {
let url = URL(string: MEMBER_LIST_URL)!
let data = try! Data(contentsOf: url)
let json = String(data: data, encoding: .utf8)
DispatchQueue.main.async {
completion(json)
}
}
}
비동기부분을 처리하는 부분만 함수로 정의하여 따로 처리해준다
나머지 메인쓰레드 부분에서는 동기로 처리하면 되기 때문에 디스패치큐를 사용할 필요가 없다.
@escaping 에 대해서
해당 클로저를 어떤 구문 밖으로 탈출 시켜서 사용하겠다는 뜻입니다.
// @escaping 선언이 없다면 구문 밖에서 사용이 불가능하기 때문에, 배열에 할당이 불가능합니다.var completionHandlers: [() -> Void] = []
func withEscaping(completion: @escaping () -> Void) {
completionHandlers.append(completion)
}
보시면 받아온 completion을 함수 구문 밖인 배열에 넣는 것을 알 수 있죠
이를 통해, 나중에 언제든 배열에서 꺼내어서 사용하겠다는 것입니다.
즉, 함수 구문 밖으로 탈출을 한 것이죠.
그렇다면 한 번 더 명시적인 예제를 만들어서 볼게요.
class Myclass {
var x = 10
func callFunc() {
withEscaping { self.x = 100 }
withoutEscaping { x = 200 }
}
var completionHandlers: [() -> Void] = []
func withEscaping(completion: @escaping () -> Void) {
completionHandler.append(completion)
}
func withoutEscaping(completion: () -> Void) {
completion()
}
}
이렇게 생긴 MyClass라는 클래스가 있죠.
그럼 한 번 메소드를 실행시켜보고 결과가 어떻게 나오는지 볼게요.
let mc = MyClass()
mc.callFunc()
print(mc.x)// 200
mc.completionHandlers.first?()
print(mc.x)// 100
callFunc()을 호출하게 되면 먼저 withoutEscaping 메소드가 클로저를 바로 호출하기때문에, x의 값이 200으로 바뀌는 것을 확인 할 수 있어요.
이후 withEscaping에서는 클로저를 바로 호출하는 것이 아니라 completionHandlers 배열에 저장을 하게 되죠