Swift에서는 lazy
키워드를 사용하여 프로퍼티가 실제로 접근되기 전까지 초기화를 지연시킬 수 있다.
이는 성능 최적화 및 불필요한 메모리 사용을 줄이는 데 유용하다. 이번 글에서는 lazy
의 동작 방식과 활용법을 깊이 있게 살펴본다.
lazy
프로퍼티란?lazy
키워드를 사용하면 프로퍼티가 처음 접근될 때까지 초기화되지 않는다. 즉, 클래스나 구조체가 인스턴스화될 때가 아니라, 해당 프로퍼티에 실제로 접근하는 순간 값이 할당된다.
class Example {
lazy var value: String = {
print("Value가 초기화됨")
return "Hello, Lazy!"
}()
}
let example = Example()
print("인스턴스 생성 완료")
print(example.value) // 여기서 초기화됨
인스턴스 생성 완료
Value가 초기화됨
Hello, Lazy!
위 코드에서 value
프로퍼티는 example.value
가 호출되기 전까지 초기화되지 않는다. 따라서 example
인스턴스를 생성할 때는 Value가 초기화됨
이 출력되지 않지만, example.value
를 호출하는 순간 초기화가 진행된다.
lazy
프로퍼티의 활용예를 들어, 네트워크 요청이나 복잡한 연산이 포함된 프로퍼티는 즉시 초기화하는 것보다 lazy
로 선언하는 것이 효율적이다.
class DataFetcher {
lazy var data: [String] = {
print("데이터 로딩 중...")
return ["Swift", "Kotlin", "Python"]
}()
}
let fetcher = DataFetcher()
print("fetcher 인스턴스 생성 완료")
print(fetcher.data) // 여기서 데이터가 로드됨
이런 방식은 리소스를 절약하는 데 도움을 준다. 객체가 생성될 때 굳이 사용되지 않는 데이터를 즉시 로딩할 필요가 없기 때문이다.
self
가 필요한 경우클래스 내부에서 self
에 의존하는 프로퍼티는 lazy
로 선언해야 한다. Swift에서는 클래스 인스턴스가 완전히 초기화되기 전에 self
를 사용할 수 없기 때문이다.
class Person {
var name: String
lazy var greeting: String = {
return "안녕하세요, 저는 \(self.name)입니다."
}()
init(name: String) {
self.name = name
}
}
let person = Person(name: "Alice")
print(person.greeting) // "안녕하세요, 저는 Alice입니다."
여기서 greeting
프로퍼티는 self.name
을 필요로 하므로 lazy
가 없으면 초기화 시점에 self
를 참조할 수 없어 오류가 발생한다.
lazy
의 한계let
과 함께 사용할 수 없음lazy
는 반드시 var
로 선언해야 한다. let
과 함께 사용할 수 없다.
class Example {
lazy let value = 42 // 오류 발생
}
이는 lazy
의 특성상 초기화 이후 값이 변경될 수 있어야 하기 때문이다. let
은 한 번 할당되면 변경할 수 없는 상수이므로 lazy
와 함께 사용할 수 없다.
struct
)에서는 mutating
문제Swift에서 구조체는 값 타입이므로, lazy
프로퍼티를 포함한 구조체 인스턴스를 변경하려면 mutating
키워드가 필요하다.
struct Example {
lazy var value: Int = {
print("초기화됨")
return 10
}()
}
var example = Example()
print(example.value) // 정상적으로 동작
하지만 let
으로 구조체를 선언하면 lazy
프로퍼티에 접근할 수 없다.
let example = Example()
print(example.value) // 오류 발생: 'self'가 불변 상태여서 접근할 수 없음
이유는 구조체가 값 타입이기 때문이다. lazy
프로퍼티가 변경될 가능성이 있으므로, let
으로 선언된 구조체에서는 이를 허용하지 않는다.
Swift의 lazy
프로퍼티는 성능 최적화 및 메모리 절약을 위한 중요한 기능이다. 특히, 무거운 연산을 지연시키거나 self
를 참조해야 하는 경우 필수적으로 사용해야 한다. 하지만 let
과 함께 사용할 수 없고, 구조체에서는 mutating
과 관련된 제약이 따르므로 신중하게 적용해야 한다.