BOID
[swift] 획득목록(Capture list), 캡쳐리스트 란? -HoonIOS 본문
안녕하세요 HoonIOS입니다. :)
이번에는 획득목록에 대해 알아보겠습니다.
우선 획득목록을 사용하는 이유는 우리는 클로저의 강한 참조를 해결하기 위해 획득 목록을 사용합니다.
획득목록이란?
- 클로저 내부에서 참조 타입을 획득하는 규칙을 제시해줄 수 있는 기능입니다.
획득목록 문법, 형태?
- 작성 위치는 클로저 내부의 매개변수 목록 이전 위치에 작성을 해줍니다.
- 참조 방식과 참조할 대상을 ( [ ] )로 둘러싼 목록 형식으로 작성을 하고 획득목록 뒤에는 in 키워드를 써줍니다.
- 획득목록에서 쓴 요소들이 참조타입이 아니라면 해당 요소들은 클로저가 생성될때 초기화가 됩니다.
획득목록 예시
var a = 0
var b = 0
let closure = { [a] in
print(a,b)
b = 20
}
a = 10
b = 10
closure() // 0 10
print(b) // 20
* 변수 a는 클러저의 획득목록을 통해 클로저가 생성될때 값 0을 획득을 했지만 b는 획득을 하지 못했습니다. 그후 a, b의 값을 10으로 변경한 후 클로저를 실행하면 a는 클로저가 생성되었을때 획득한 값 0을 가지지만 b는 변경된 값을 사용합니다.
( 즉 a는 클로저가 생성됨과 동시에 획득목록 내에 다시 a라는 이름의 상수로 초기화한 것입니다. )
- 획득목록의 요소가 참조 타입이라면 결과는 달라질 수 있습니다.
class SimpleClass {
var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
print(x.value, y.value)
}
x.value = 10
y.value = 10
closure() // 10 10
* 위 예시를 보면 변수 x는 초기에 0이라는 값을 획득했지만 y는 획득목록에 별도로 명시되지 않았습니다. 그렇지만 두 변수를 모두 참조타입의 인스턴스가 있기 때문에 동작은 같습니다. 둘다 x.value, y.value을 10으로 준값으로 바뀐것을 볼수 있습니다.
- 참조 타입은 값 타입과 달리 획득목록에 어떤 방식(강한 획득, 약한 획득, 미소유 획득)을 참조할 것인지 정해줄 수 있습니다
- 방식에 따라서 참조 횟수를 증가시킬지 결정할수 있습니다.
( 약한 획득, 미소유 획득 은 참조횟수를 증가시키지 않습니다. )
- 세 가지 방식 중 약한 획득을 조심해야 됩니다. 약한 획득을 하게 되면 획득목록에서 획득하는 상수가 옵셔널 상수로 지정해야 합니다.
- 옵셔널 상수로 지정하는 이유는 바로 약한 획득한 상수를 사용하려고 할 때 이미 메모리에서 해제된 상태일수 있기 때문입니다. 잘못 접근을 하면 오류가 발생하겠죠?
클로저의 획득목록이란?
* x를 약한 참조 y를 미소유 참조로 지정을 했습니다.
- x는 약한 참조이므로 x가 참조하는 인스턴스의 참조 횟수를 증가하지 않습니다. x가 참조하는 인스턴스가 메모리 해제되면 클로저 내부에서도 더 이상 참조가 불가능하다는 것을 알 수 있습니다.
( x의 value 프로퍼티 값이 nil로 초기화된 것을 볼 수 있습니다. )
- y는 미소유 참조를 했으므로 클로저가 참조횟수를 증가시키지 않는다. 그렇지만 만약에 메모리에서 해제된 상태에서 사용하려면 컴파일오류가 발생합니다.
* 클로저에 self를 미소유참조를 명시해주는 예시를 살펴보겠습니다.
- 이 코드는 지연 프로퍼티인 introduce 프로퍼티의 클로저가 self를 미소유 참조하도록 명시를 해주었습니다.
- 미소유 참조를 한다는 것은 해당 인스턴스가 해제되거나 존재하지 않으면 실행 중 오류가 발생하는 특성이 있는데 따라서 이 예제에서 self를 미소유 참조한다는 것은 실행 중에 인스턴스가 사라질 가능성이 없다고 볼 수 있습니다.
- 그렇지만 만약에 진짜 만에 하나 클로저가 다른 곳에서 참조하게 된 후 인스턴스가 메모리에서 해제되면 앱이 강제 종료될 수 있는 큰 문제를 야기할 수 있습니다. 따라서 미소유 참조는 신중히 사용을 해야 되고, 문제가 될 소지가 있다면 약한참조를 사용하면 됩니다.
( 다 아시겠지만, yagom을 인스턴스 해제를 위해 nil을 주고 싶으면 변수에 선언을 해줄 때 옵셔널을 붙여주어야 합니다. )
이번에는 클로저의 획득 목록의 미소유 참조로 인한 접근 문제에 대해 알아보겠습니다.
* 위 예제에서 Lee의 introduce가 yeong의 introduce를 참조하고 있습니다. 그다음 yeong 인스턴스를 메모리 해제해주고 yeong?.introduce( ) 와 Lee?.introduce( )를 print해보면 yeong?.introduce( )은 nil이 출력이 되고, Lee?.introduce( )는 이미 해제해준 yeong을 참조하고 있으므로 에러가 뜰 수밖에 없습니다.
- 만약 미소유 참조로 문제가 발생 시 약한참조로 변경하고 옵셔널을 사용해도 무방합니다.
이번에는 ARC에서 획득 목록에 대해 알아봤습니다... 저도 개린이인지라 개인 공부할 때도 못 봤었던 내용이라 좀 이해하기가 힘들었던 부분이 있었습니다.
공부하면서 그냥 넘어가면 안 될 거라는 생각이 들어서 계속해서 공부해야 될 거 같습니다.
긴 글 읽어주셔서 감사합니다 :)
'swift 시작기' 카테고리의 다른 글
[swift] 함수에서 발생한 오류 알리기(try ,try! ,try? , do - catch) - HoonIOS (3) | 2021.04.06 |
---|---|
[swift] 오류처리란? -HoonIOS (0) | 2021.04.06 |
[swift] 클로저의 강한참조, 강한참조 순환 - HoonIOS (0) | 2021.04.01 |
[swift] 미소유 옵셔널 참조와 암시적 추출 옵셔널 프로퍼티 - HoonIOS (0) | 2021.04.01 |
[swift] 강한참조, 강한참조 순환, 약한참조, 미소유참조- HoonIOS (0) | 2021.03.30 |