티스토리 뷰

Swift

[swift] escaping closure

진태우 2019. 4. 14. 15:11

 

여러 method를 보면 클로저의 타입에 @escaping이란 단어가 붙어 있는게 종종 보입니다.

이게 뭔지 궁금했는데 이제야(?) 알아보려고 합니다!!

그 전에 먼저 @noescape 키워드 부터 알아 보겠습니다.

아래는 공식 문서의 예제 코드입니다.

func someFunctionWithNonescapingClosure(closure: @noescape () -> Void) {
    // 2. do something...

    // 3. 클로저가 실행된다.
    closure()
}

class SomeClass {
    var x = 10
    func doSomething() {
        // 1. 클로저를 함수의 인자로 전달한다.
        someFunctionWithNonescapingClosure { 
            x = 200 
            // 4. 클로저가 종료되고, 클로저는 메모리에서 지워진다.
        }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)    // Prints "200"

 

함수가 실행되면 클로저가 함수의 인자로 전달되고 전달된 클로저는 즉시 실행됩니다.

기본적으로 함수의 인자로 전달된 값은 함수의 외부에서 접근이 불가능합니다. 때문에 함수 안에서만 접근이 가능하죠. 그래서 이름이 탈출불가(?)인가 봅니다...

클로저의 라이프사이클은 위에 표시한 순서대로 실행됩니다.

클로저는 @noescape가 기본값이기 때문에 일반적으로 @noescape 키워드를 사용하지 않습니다!!

 

이번에는 @escaping 키워드를 예제 코드를 통해 알아 보겠습니다.

var completionHandlers: [() -> Void] = []
    
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
    
class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
    }
}
    
let instance = SomeClass()
completionHandlers.first?()
print(instance.x)    // Prints "100"

못보던 completionHandlers라는 변수가 생겼습니다!!

이것은 클로저를 저장하는 변수이고, someFunctionWithEscapingClosure 메서드를 보면 클로저를 외부에서 선언한 변수에 저장하는 것을 볼 수 있습니다.

이렇게 @escaping 키워드를 사용하면 함수 외부에서도 클로저에 대해 접근이 가능합니다.

 

그럼 @escaping 는 어떤 경우에서 사용하는지 보겠습니다.

Alamofire.request(urlRequest).responseJSON { response in
    // handle response
}

위 코드는 Alamofire 라이브러리를 사용하여 통신을 하는 코드입니다.

일반적으로 통신을 하면 반환된 데이터를 가지고 작업을 하게 되는데, 여기서 중요한 점은 데이터가 반환된 후 클로저가 실행되야 한다는 점입니다.

public func responseJSON(
    queue: DispatchQueue? = nil,
    options: JSONSerialization.ReadingOptions = .allowFragments,
    completionHandler: @escaping (DataResponse<Any>) -> Void)
    -> Self {
}

Alamofire의 responseJSON 함수를 보면 completionHandler가 @escaping 으로 되어 있는걸 볼 수 있습니다. 이는 함수 외부에서 접근이 가능하다는 것이겠죠!

그럼 클로저를 저장하는 변수를 선언해 저장하고, 모든 작업이 끝난 후에 클로저를 실행해 줌으로써 실행 순서를 정할 수가 있습니다.

responseJSON 함수에서도 @escaping을 사용해 통신 작업이 모두 끝나고 클로저를 실행해서 항상 통신작업이 끝나고 클로저가 실행되게 하는 것입니다.

 

또 한가지는 클로저를 인자로 전달했는데 UI를 수정해야 코드가 있는 경우입니다.

public func changeView(completionHandler: @escaping () -> ()) {
    // do something..
    
    DispatchQueue.main.async {
    	completionHandler()
    }
}

위 코드는 UI를 수정하는 클로저를 전달하고, 클로저를 메인큐로 실행시키는 코드입니다.

UI가 변경되는 코드는 항상 메인큐에서 실행되야 하기 때문에 @escaping 클로저를 사용하지 않으면 컴파일 에러가 발생합니다.

 

 

- Notion page

https://www.notion.so/taewoojin/swift-escaping-closure-c3b71f4c89594f7c9a173e9d62190c43

'Swift' 카테고리의 다른 글

[Swift] Documentation Comments  (0) 2020.05.29
[swift] AVFoundation를 이용한 Video Record 만들어보기  (2) 2020.03.25
[swift] Optional  (0) 2019.03.29
[swift] Enum  (0) 2019.03.29
정수값에 구분자를 넣어보자!!  (0) 2018.08.21
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함