programming/Swift
[Swift/iOS] 캡쳐리스트 Capture List , 탈출 클로저 escaping Closure, 자동클로저 AutoClosure from 공식문서
마들브라더
2023. 4. 27. 02:47
! 공식문서를 참고한 글입니다
캡쳐리스트 Capture Lists
기본적으로 클로저는 주변에서 클로저 안에서 사용할 때 필요한 상수와 변수를 캡쳐함
이때 어떻게 밸류를 캡쳐할 것인지 캡쳐리스트를 사용해서 컨트롤 할 수 있음
var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure() // Prints "0 10"
캡처리스트는 대괄호를 사용하여 파라미터 앞에 명시함
클로저에서 매개변수 이름, 타입, 반환타입을 생략하더라도 캡처리스트를 사용하려면 in 키워드를 사용해야함
캡처리스트는 생성될 때 초기화 되기 때문에 a는 0으로 표시됨
만약 캡쳐한 변수가 참조타입이라면 원래의 인스턴스를 참조해서 캡쳐한다고 생각할 수 있음
class SimpleClass {
var value: Int = 0
}
var x = SimpleClass() // 클래스는 참조타입
var y = 0 // 값타입
let closure = { [x, y] in
print(x.value, y)
}
x.value = 10
y = 10
closure() // Prints "10 0"
클래스를 캡쳐하는 경우에는 weak나 unowned로 표시해서 강한 순환 참조를 해결하자
myFunction { print(self.title) } // implicit 강한 참조
myFunction { [self] in print(self.title) } // explicit 강한 참조
myFunction { [weak self] in print(self!.title) } // weak capture 사용
myFunction { [unowned self] in print(self.title) } // unowned capture 사용
// Weak capture of "self.parent" as "parent"
// 지정된 이름으로 바인드 할 수 있음
myFunction { [weak parent = self.parent] in print(parent!.title) }
https://modelinspring.tistory.com/79 글의 탈출클로저에 이어서..
이스케이핑(탈출) 클로저 Escaping Closures
...
이스케이핑 클로저를 사용하고, self를 참조할 때에는 명시적으로 나타내주어야함
func 이스케이핑함수(closure: @escaping () -> Void) {
closure()
}
func 논이스케이핑함수(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
이스케이핑함수 {
x = 100 // Reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit 에러 발생
}
논이스케이핑함수 {
x = 200
}
}
}
논이스케이핑 함수에서는 self를 쓰지 않아도 암시적으로 캡쳐할 수 있지만,
이스케이핑 함수에서는 self를 써야함
class SomeClass {
var x = 10
func doSomething() {
이스케이핑함수 {
self.x = 100
}
논이스케이핑함수 {
x = 200
}
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) // Prints "200"
캡쳐리스트에 self를 넣어서 해결할 수도 있음
class SomeClass {
var x = 10
func doSomething() {
이스케이핑함수 { [self] in
x = 100
}
논이스케이핑함수 {
x = 200
}
}
}
자동클로저 Autoclosures
인자 값이 없는 특정 구문을 자동으로 클로저로 감싸주는 것
함수의 인자로 클로저를 받는 경우 괄호 없이 그냥 구문으로 넘길 수 있게 함
func test(closure: () -> Void) {
closure()
}
test {
print("code")
}
func test2(closure: @autoclosure () -> Void) {
closure()
}
test2(closure: print("code22"))