지연 저장 속성 (Lazy Stored Property) 은 인스턴스가 초기화 되는 시점이 아니라 속성에 처음 접근하는 시점에 초기화됩니다. lazy 키워드를 사용하여 선언하는 방법은 아래와 같습니다.
lazy var name: Type = DefaultValue
초기화 시점이 지연되기 때문에 몇 가지 제한이 있습니다. 인스턴스가 초기화된 이후에 지연 저장 속성은 개별적으로 초기화가 됩니다. 그렇기 때문에 변수(lazy var)가 아닌 상수(lazy let)로 선언은 불가능 합니다. 또한 생성자에서 초기화 하지 않기 때문에 선언 시점에 기본값을 저장해주어야 합니다.
이미지를 저장하는 구조체 예제를 살펴보겠습니다.
struct Image {
init() {
print("New Image")
}
}
예제이므로 실제로 이미지는 저장하지 않고 초기화 함수가 불리는지만 print 함수로 파악하도록 하겠습니다.
struct BlogPost {
let title: String = "Title"
let content: String = "Content"
let preview: Image = Image()
}
BlogPost 구조체를 정의하였습니다. title 과 content 는 문자열이기 때문에 메모리에 저장되는 크기가 크지 않습니다. 하지만 preview 는 이미지이기 때문에 바이너리 형태로 저장됩니다. 문자열에 비해 수십배에서 수백배까지 크기가 큽니다.
let post = BlogPost()
// Prints "New Image"
인스턴스가 초기화 되는 시점에 새로운 이미지(Image) 인스턴스가 저장됩니다. 매번 인스턴스를 생성할 때 마다 파일이나 네트워크에서 이미지를 가져온 다음에 메모리 공간에 복사해야하기 때문에 오버헤드가 발생합니다. preview 속성을 항상 사용해야 한다면 어쩔 수 없지만 이 속성에 접근하지 않는 경우에는 불필요한 메모리를 낭비하는 것입니다.
지연 저장 속성을 이용하여 이 문제를 해결해보겠습니다.
struct LazyBlogPost {
let title: String = "Title"
let content: String = "Content"
lazy var preview: Image = Image()
}
let post = LazyBlogPost()
// Prints Nothing
post.preview // 컴파일 오류 발생
preview 에 접근하는 시점에 post 의 preview 값을 바꿔야 하는데 상수(let) 으로 선언되어 있기 때문에 값을 바꿀 수 없습니다. 지연 저장 속성을 사용한다면 인스턴스를 변수(var)에 저장해야합니다.
var post = LazyBlogPost()
post.preview
// Prints "New Image"
다음으로는 초기화 시점이 같은 속성에 접근할 때 lazy 키워드를 사용하는 경우를 알아보겠습니다. Date 의 경우 적절하게 포맷팅하여 String 으로 사용하는 경우가 많습니다.
struct LazyDate {
let date: Date = Date()
var formattedDate: String = {
let f = DateFormatter()
f.dateStyle = .long
f.timeStyle = .medium
return f.string(from: date) // 컴파일 에러 발생
}()
}
formattedDate 에 Date 를 포맷팅한 String 값이 저장될 때 date 속성에 접근하게 됩니다. 그런데 formattedDate 와 date 의 초기화 시점이 같기 때문에 컴파일 에러가 발생하게 됩니다.
struct LazyDate {
let date: Date = Date()
lazy var formattedDate: String = {
let f = DateFormatter()
f.dateStyle = .long
f.timeStyle = .medium
return f.string(from: date)
}()
}
formattedDate 를 지연 저장 속성으로 선언하여 문제를 해결하였습니다.
정리
- 인스턴스가 초기화될 때가 아닌 접근하는 시점에 초기화되는 지연(lazy) 저장 속성을 알아보았습니다.
- 지연 저장 속성을 활용하여 메모리 낭비를 해소할 수 있습니다.
- 초기화 시점이 같은 속성에 접근할 때도 활용할 수 있습니다.
'Swift' 카테고리의 다른 글
[SwiftUI] Property wrappers for data flow (0) | 2020.03.10 |
---|---|
[Swift] Computed Property 는 언제 쓰는지 알아보자 (0) | 2019.12.15 |
[Swift] Namespace 네임스페이스 란? (Struct, Enum 활용) (0) | 2019.12.15 |
[Swift] Enum 열거형 정복하기 2편 (Enum Case Pattern) (0) | 2019.12.15 |
[Swift] Enum 열거형 정복하기 1편 (Raw, Associated Values) (0) | 2019.12.15 |