"A lazy stored property is a property whose initial value is not calculated until the first time it is used", 애플 공식 문서
Lazy 변수는 처음 사용되기 전까지 연산이 되지 않는다.
1. lazy는 반드시 var와 함께 쓰여야 한다.
lazy 는 반드시 var와 사용되어야 한다. 기본적으로 lazy로 선언된 변수는 초기에는 값이 존재하지 않고 이후에 값이 생기는 것이기 때문에 let 으로는 선언될 수 없다.
2. struct, class
기본적으로 lazy는 struct와 class에서만 사용할 수 있다
3. lazy vs Computed Property
Computed Property에는 lazy 키워드를 사용할 수 없다. lazy는 처음 사용될 때 메모리에 값을 올리고 그 이후 부터는 계속해서 메모리에 올라온 값을 사용한다. 사용할 때마다 값을 연산하여 사용하는 Computed Property에는 사용할 수 없다.
4. lazy and closure
lazy에 어떤 특별한 연산을 통해 값을 넣어주기 위해서는 코드 실행 블록인 closure를 사용한다.
class나 struct의 다른 프로퍼티의 값을 lazy 변수에서 사용하기 위해서는 closure내에서 self를 통해 접근이 가능하다. 기본적으로 일반 변수들은 클래스가 생성된 이후에 접근이 가능하기 때문에 클래스내의 다른 영역(메소드, 일반 프로퍼티)에서는 self를 통해 접근할 수 없지만 lazy 키워드가 붙으면 생성 후 추후에 접근할 것이라는 의미이기 때문에 closure내에서 self로 접근이 가능하다.
class Person {
var name:String
lazy var greeting:String = {
return "Hello my name is \((self.name))"
}()
init(name:String){
self.name = name
}
}
var me = Person(name:"John")
print(me.greeting // Hello my name is John
me.name = "James"
print(me.greeting // Hello my name is John
lazy var greeting을 보면 클로저 내부에서 self.name을 통해 name프로퍼티에 접근한다. 이렇게 클래스 내부의 클로저에서 클래스 객체를 self 로 참조한다면 메모리 누수가 발생하는 위험이 있는데 뒤의 ()를 통해 그 즉시 실행하고 결과를 돌려주고 끝나버리기 때문에 메모리 누수의 걱정은 없다.
또한 프로퍼티가 James으로 변경이 되어도 처음 사용할 때 메모리에는 John이 올라가 있기 때문에 John이 출력이 된다.
class Person {
var name:String
lazy var greeting: ()->String = { [weak self] in
return "Hello my name is \(((self?.name))!)"
}
init(name:String){
self.name = name
}
}
var me = Person(name:"John")
print(me.greeting()) // Hello my name is John
me.name = "James"
print(me.greeting()) // Hello my name is James
만일 변수가 lazy var greeting:String이 아닌 lazy var greeting:()->String으로 클로저 실행의 결과를 담는 것이 아닌 클로저 자체를 담고 있는 변수라면 반드시 [weak self]를 통해 메모리 누수를 방지해주어야 한다.
또한 값이 아닌 클로저 자체가 메모리에 올라가 있고 self 는 내부에서 계속해서 클래스를 참조하기 때문에 계속 John이 출력이 되는 것이 아닌 James가 출력이 되는 것이다.