iOS스터디/Swift

[Swift] @escaping Closure

슬라임 통통 2021. 3. 9. 23:04
728x90

시작하기전에 클로져

func add(_ i : Int, _ j : Int, _ handler: (Int) -> Void){
	let sum = i + j
    handler(sum)
}

add(3,4 {(result : Int) -> Void in 
	print("3 + 4 = \(result)")
})

 

 

자세한 이야기

 

함수의 파라미터로 클로져가 전달될 때 escaping 또는noescaping closure가 사용됩니다.

 

클로저가 함수로부터 Escape한다는 것은 해당 함수의 인자로 클로저가 전달되지만, 함수가 반환된 후 실행 되는 것을 의미합니다.수의 인자가 함수의 영역을 탈출하여 함수 밖에서 사용할 수 있는 개념은 기존에 우리가 알고 있던 변수의 scope 개념을 무시합니다. 왜냐하면 함수에서 선언된 로컬 변수가 로컬 변수의 영역을 뛰어넘어 함수 밖 에서도 유효하기 때문입니다.

 

Escaping Closure를 활용하면 통해서 함수 사이에 실행 순서를 정할 수 있습니다.

 

함수의 실행 순서를 보장 받을 수 있는 것은 상당히 중요한 기능입니다. 왜냐하면, 이 순서 보장은 비동기 함수의 경우도 포함하기 때문입니다. 

 

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

}

눈여겨 볼 부분은 completionHandler입니다. 이 completionHandler Escaping Closure 형태로 작성되어 있습니다. 즉, completionHandler responseJSON(queue:options:completionHandler:) 함수가 반환되고(완전히 서버로부터 값을 가져 온 상태에서) 실행됩니다. 그 부분이 바로 trailing closure 형태로 작성되어 있는 { response in } 부분입니다.

 

Escaping Closure를 통해서 클로저 인자는 함수로부터 빠져나올 수(outLive) 있습니다. Swift3 이후부터는 기본적으로 함수의 인자로 들어오는 클로저가 함수 밖에서 사용할 수 없도록 되어 있습니다. 즉 기본적으로 클로저를 함수 외부의 저장소에 저장하거나, GCD를 이용하여 다른 쓰레드에서 해당 클로저를 실행시키는 것이 불가능합니다. 하지만 이는 Escaping Closure를 통해 사용 가능하고, 클로저 타입 앞에 @escaping 키워드를 넣어주면 Closure는 Escaping Closure가 됩니다.

 

 

정리

 

Noescaping (아무말 없을 시 기본값 swift 3이후부터

함수 외부에서 사용 금지 .

프로퍼티로 설정하면 에러

class MyClass{
	var prop : (()->())!
    func closureFunc(_ arg: ()->()){
    	self.prop = arg  //Error
    }
}

다른 함수의 프로퍼티 (noescaping -> noescaping) 전달 가능. 어차피 같혀있기 때문.

func closureFunc(_ arg: ()->()){
	otherFunc(arg)
}

func otherFunc(_ arg: ()-> ()){
	arg()
}

 

 

escaping 

@escaping을 파라미터 타입 앞에 붙여주면 설정됨.

파라미터 클로져를 함수 외부에서 사용하기 가능.

class MyClass2{
	var prop : (()->())!
    func closureFunc(_ arg: @escaping()->()){
    	self.prop = arg
    }
}

 

 

autoclosure

파라미터가 없는 표현식을 클로저로 변환

파라미터가 없는 클로저

 

func dolt (_ arg: ()->()){
	//Code
}
dolt({value += 10})

func dolt2(_ arg: @autoclosure () -> ()) {
	//Code
}
dolt2( value += 10 )

밑의 dolt2에서 중괄호가 없어도 알아서 알아들음.

 

오토 클로져는 noescape으로 자동설정 되어있음.

 

 

 

www.youtube.com/watch?v=kolg2dim3d4

 

 

 

 

 

728x90
반응형