본문 바로가기

iOS

[iOS] Completion Handler

Completion Handler

본 문서에는 평소에 공부를 진행하며 한번 정리가 필요하다고 생각했던 Completion Handler에 대한 내용을 기재한다.


Prerequisite


Completion Handler 개념은 알면 알수록 어려운 개념이다..

Closure (특히 Trailing Closure) 에 대한 이해가 부족하다면 Closure Summary 를 비롯한 다양한 레퍼런스들을 앞서 살펴보는 것이 좋지만 Trailing Closure 개념에 대해 간단히 정리하고 본 내용으로 들어가도록 한다.


Trailing Closure

Trailing Closure, 후행 클로저는 함수의 마지막 인자로 클로저 표현식을 함수에 전달하거나 클로저 표현식이 긴 경우에 사용한다. (매우 꿀 기능이다!)

아래 코드 예시를 살펴보도록 하자.

func travel(action: () -> Void) {
    print("I'm getting ready to go.")
    action()
    print("I arrived")
}

travel 메서드는 인자로 action 이라는 Closure를 채택하고 있다,

action은 함수 내부에서 두 번의 프린트 사이에 실행된다.

우리는 위 travel 메서드를 아래와 같은 방식으로 사용할 수 있다.

travel() {
    print("I'm driving in my car")
}

위 예시의 경우에는 인자가 필요없기 때문에 인자 표현을 위한 () 또한 생략이 가능하다.

travel {
    print("I'm driving in my car")
}


Completion Handler?


자 이제는 Completion Handler가 무엇인지 살펴보도록 한다.

사용자가 앱을 사용하는 동안에 앱을 업데이트를 진행하고 개발자는 업데이트가 끝나면 이를 반드시 사용자에게 알려야 하는 상황이라고 가정해보자.

개발자가 업데이트가 끝났음을 알리기 위해 내부에는 "업데이트가 정상적으로 진행되었습니다" 라는 문구가 작성되어 있는 alert창을 띄운다.

이렇듯 Completion Handler는 어떠한 일이 끝났을 떄 진행할 업무를 담당한다.


Introduce


아래 코드는 모두가 익숙할만한 다음 ViewController로 화면을 전환하는 코드다.

import UIKit

let firstVC = UIViewController()
let nextVC = UIViewContrller()

firstVC.present(nextVC, animated: true, completion: nil)

present 메서드 마지막 파라미터 completion에 주목하자.

completion 파라미터에는 ()->() 또는 ()->Void 타입의 클로저 블락을 사용할 수 있다.

아래와 같이 completion 파라미터에 클로저를 적용시켜본다.

firstVC.present(nextVC, animated: true, completion: { () in print("화면전환 완료")})

위 메서드가 정상적으로 실행되면 nextVC가 팝업되면서 콘솔창에는 "화면전환 완료" 라는 문자열이 출력된다.

위 코드는 아래와 같이 축약 또한 가능하다.

firstVC.present(nextVC, animated: true, completion: { print("화면전환 완료")})

인자값이 없으니 이를 생략하고 in 키워드 또한 생략이 가능하니 이 또한 생략했다!

놀라운건 이를 한번 더 축약할 수 있다는 점이다.

firstVC.present(nextVC, animated: true) { print ("화면전환 완료")}

앞서 간단히 살펴봤던 Trailing Closure를 이용한 축약법이다.


Completion Handler 디자인


이제는 위 예시 present 메소드처럼 디자인을 해보자.

일이 끝나면 사장님께 퇴근하겠다는 얘기를 전달하는 클로저를 작성해본다!


let handleBlock: (Bool) -> Void = { doneWork in 
 if doneWork {
     print("퇴근하겠습니다")
 }
}

handleBlock(true)       // 퇴근하겠습니다

이를 $ 사인을 이용해 인자를 처리해보도록 한다.


let handleBlock: (Bool) -> Void = {
    if $0 {     // replace $0 = doneWork
        print("퇴근하겠습니다")
    }
}

Completion Handler를 통한 데이터 전달


Alamofire와 같은 통신 라이브러리를 이용해 JSON 형태의 데이터를 받아올 떄 아래와 같은 코드 형태를 많이 살펴봤을 것이다.

Alamofire.request("https://google.com").responseJSON { response in
    print(response)
}

메서드의 request가 서버로 전송되어 이에 대한 결과값이 response 인자에 담겨 이를 클로저 내부에서 사용할 수 있게된다.

이렇듯 Swift 를 이용하다보면 함수의 마지막 인자로 Closure를 적용하는 경우를 심심치않게? 살펴볼 수 있다.

이는 함수가 종료된 직후(Called at the back)의 이벤트 처리를 위해 매우 많이 사용된다.

위 개념은 꼭 반복하여 익히도록 하자.


Reference

'iOS' 카테고리의 다른 글

[iOS] UIResponder  (0) 2020.05.29
[iOS] NavigationController RootView 변경  (0) 2020.05.26
[iOS] Firebase  (0) 2020.05.24
[iOS] Dive in Closure  (0) 2020.05.24
[iOS] AppDelegate 그리고 SceneDelegate  (0) 2020.05.20