Closure Capture List

작성일

Closure Capture List

class Car {
  var totalDrivingDistance = 0.0
  var totalUsedGas = 0.0

  lazy var gasMileage: () -> Double = {
    return self.totalDrivingDistance / self.totalUsedGas
  }

  func drive() {
    self.totalDrivingDistance = 1200.0
    self.totalUsedGas = 73.0
  }

  deinit {
    print("car deinit")
  }
}

var myCar: Car? = Car()
myCar?.drive() // 아직 클로져가 발생하지않았고, 따라서 강한참조사이클은 아직 발생하지 않는다.  
// 따라서 이 시점에서 nil를 할당하면,
myCar = nil // deinit이 실행되면서, 정상적으로 메모리에서 내려가는걸 볼 수 있다.

myCar?.gasMileage() // 강한참조사이클이 발생한다.
myCar = nil // 강한참조사이클이기 때문에 소멸자인 deinit이 실행되지 않는다.

value Type

var a = 0
var b = 0
let c = { print(a, b) }

a = 1
b = 2
c()

를 출력해보면

1 2

가 출력되는걸 볼 수 있다.
여기서 클로져의 캡처현상을 사용하면,

var a = 0
var b = 0
let c = { [a] in print(a, b) }

a = 1
b = 2
c()

출력

0 2 

가 출력되는걸 볼 수 있다.
값형식은 캡처시점에 복사되었던 값이 출력이 된다.
참조대신 복사본이 출력된다.

Reference Type

기본

{ [weak instanceName, unowned instancename] in 
   statements
}

활용

class Car {
  var totalDrivingDistance = 0.0
  var totalUsedGas = 0.0

  lazy var gasMileage: () -> Double = { [weak self] in
    guard let strongSelf = self else { return 0.0}
    return strongSelf.totalDrivingDistance / strongSelf.totalUsedGas
  }

  func drive() {
    self.totalDrivingDistance = 1200.0
    self.totalUsedGas = 73.0
  }

  deinit {
    print("car deinit")
  }
}

약한 참조는 옵셔널값이라 guard let을 사용하여 언래핑해줘서 사용해야한다.
이때 아까

var myCar: Car? = Car()
myCar?.drive()

myCar?.gasMileage()
myCar = nil

를 다시한번 실행시켜보면,

car deinit

이렇게 메모리에서 내려가서 deinit소멸자가 실행되는걸 볼 수 있다.