iOS 응용 (swift)
[iOS - swift] @_implicitSelfCapture, implicit self capture (클로저 안에서 self 키워드 생략 방법, Task 블록에서 self 안쓰는 이유)
jake-kim
2023. 7. 6. 01:59
capture 안에서 외부에 접근 시 self 붙이는 이유
- swift에서 capture안에서 closure 외부에 접근하려면 self 키워드를 명시적으로 붙이지 않으면 컴파일 에러가 발생
- swift에서 캡쳐를 하는 블록에서는 항상 self를 명시적으로 붙여주어야 하는데, 이 목적은 memory leak을 유발할 수 있는 곳에서는 self를 명시적으로 붙이게하여 개발자에게 leak의 위험을 알리는 목적이 존재
- 구체적인 내용: https://github.com/apple/swift-evolution/blob/main/proposals/0269-implicit-self-explicit-capture.md
@_implicitSelfCapture 개념
- swift에서 capture안에서 closure 외부에 접근하려면 self 키워드를 명시적으로 붙여주어야 하는데 이 self키워드를 생략해주게 하는 키워드
- leak의 위험이 없는 capture closure에서는 self 키워드가 불필요하므로 @_implicitSelfCapture가 등장
@_implicitSelfCapture 사용방법
- 만약 메소드에서 파라미터로 closure를 받을때, argument label 왼쪽에 @_implicitSelfCapture를 사용하면 해당 클로저에서는 self 생략이 가능
class Person {
var name = "jake"
func myFunc1() {
}
func myFunc3(@_implicitSelfCapture _: @escaping () -> Void) {
myFunc3 {
myFunc1()
// ok
}
}
}
- @_implicitSelfCapture 없는 메소드는 컴파일 에러가 발생

Swift Concurrency의 Task 블록
- Task 블록에서도 self 키워드 생략이 가능한데 이곳에서도 내부적으로는 @_implicitSelfCapture 키워드를 사용해서 구현한 것
- Apple에서 Task 블록에서는 self와 관련된 memory leak의 위험이 없다고 판단하여 @_implicitSelfCapture를 사용하여 self를 생각하지 말고 그냥 편하게 사용하라는 의도
class ViewController: UIViewController {
var mainTitle = "김종권의 iOS 앱 개발 알아가기"
override func viewDidLoad() {
super.viewDidLoad()
Task {
print(mainTitle)
}
}
}
- Task와 같은 MyTask를 만들면, 아래처럼 argument label 옆에 @_implicitSelfCapture를 붙인 형태
func MyTask(@_implicitSelfCapture closure: @escaping () -> Void) {
}
class ViewController: UIViewController {
var mainTitle = "김종권의 iOS 앱 개발 알아가기"
override func viewDidLoad() {
super.viewDidLoad()
Task {
print(mainTitle) // OK
}
MyTask {
print(mainTitle) // OK
}
}
}
* 전체 코드: https://github.com/JK0369/ExImplicitSelfCapture
* 참고
https://github.com/apple/swift-evolution/blob/main/proposals/0269-implicit-self-explicit-capture.md
https://forums.swift.org/t/why-task-doesnt-need-explicit-use-of-self/58748