이번에는 프로퍼티에 대해서 글을 포스팅 하려고 하는데요. 이번 프로퍼티에 대한 내용은 제가 좀 개인적으로 헷갈려해서 여러 개로 나누어서 정리를 해볼까 합니다!
우선 프로퍼티에 대한 개념 먼저 알고 시작을 해야겠죠?
프로퍼티란?
우선 프로퍼티(Property)는 클래스, 구조체 또는 열거형 등의 데이터 타입 내부에 선언되어 있는 변수 또는 상수입니다. 클래스와 구조체 내부에서 값을 저장하거나 계산하는 데 사용되며, 해당 인스턴스의 속성을 나타냅니다.
근데 Swift에서는 이 프로퍼티가 크게 3가지로 나누어지게 됩니다.
- Stored Property : 저장 프로퍼티
- Computed Property : 연산 프로퍼티
- Type Property : 타입 프로퍼티
우선 이번 시간에는 간단하게 저장 프로퍼티(Stored Property)에 대해서 알아보도록 하겠습니다.
저장 프로퍼티란?
저장 프로퍼티는 값을 저장하기 위해 메모리 공간을 할당하는 일반적인 프로퍼티 유형입니다. 클래스와 구조체에서 사용할 수 있으며, var 키워드를 사용하여 가변(mutable) 저장 프로퍼티를 선언할 수 있고 let 키워드를 사용하여 불변(immutable) 저장 프로파일을 선언할 수 있습니다.
글로만 설명을 하면 이해가 잘 안 되니 소스도 함께 보겠습니다!
struct Person {
var name: String // 가변 저장 프로퍼티
let age: Int // 불변 저장 프로퍼티
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
var person1 = Person(name: "John", age: 25)
print(person1.name) // 출력 결과: John
person1.name = "Alice"
print(person1.name) // 출력 결과: Alice
let person2 = Person(name: "Bob", age: 30)
// person2.age = 35 // 에러 발생! 불변 저장 프로퍼티는 값을 변경할 수 없습니다.
아마 소스 자체에서 크게 어려운 부분은 없을 겁니다. 왜냐하면 우리가 지금까지 너무 아무렇지 않게 클래스와 구조체에서 계속 써왔거든요!
위의 예제에서 Person 구조체는 name과 age라는 두 개의 저장 프로퍼티를 가지고 있습니다. name은 가변(변경 가능한) 저장 프로퍼티이므로 값을 변경할 수 있습니다.
반면에 age는 불변(값을 변경할 수 없는) 저장 프로파일이므로 초기화 이 후에 값이 변경되지 않습니다.
예제에서 보듯이, 구조체나 클래스 내부에서 선언된 변수나 상수가 해당 인스턴스의 속성으로 사용되어 값을 유지하는 것을 볼 수 있습니다.
저장 프로퍼티는 초기값이 있어야 하기 때문에 아래 소스처럼 사용 되어야 하는데요.
class Man1{
var age : Int = 22
var weight : Double = 60.5
}
class Man2{
var age : Int?
var weigth : Double!
}
Man1에는 초기값이 age는 22, weight은 60.5로 되어 있습니다.
"그럼 Man2는 초기값이 없는 거 아니야?" 라고 생각하실 수도 있지만 아닙니다!
Swift에서는 프로퍼티가 초기값을 가져야 하는 것은 맞지만, 프로퍼티를 옵셔널로 선언하면 초기값이 필요하지 않습니다. 그 이유는 옵셔널 프로퍼티는 값을 가지거나 'nil'일 수 있기 때문입니다.
지연 저장 프로퍼티(Lazy Stored Property)
자 그리고 저장 프로퍼티에서 조금 더 들어가면 지연 저장 프로퍼티(Lazy Stored Property)라는 것도 있습니다. 이 내용은 예전에 포스팅한 것이 있는데 참고하실 분들은 여기를 참고하시면 될 것 같고 이 포스팅에서도 간단하게 한 번 정리를 해보겠습니다.
지연 저장 프로퍼티는 짧게 설명하자면 호출되기 전에는 선언만 되고 초기화되지 않은 상태로 있다가, 프로퍼티 호출이 되는 순간에 초기화를 하는 저장 프로퍼티입니다.
말이 좀 어렵죠?
이 내용 역시 소스랑 같이 보겠습니다.
class DataManager {
// 이 지연 저장 프로퍼티는 처음으로 접근될 때 초기화됩니다.
lazy var data: [String] = {
print("Calculating data...")
return ["Item 1", "Item 2", "Item 3"]
}()
init() {
// 여기에서는 'data' 프로퍼티에 직접 접근하지 않으므로 초기화되지 않습니다.
}
func fetchData() {
// 'data' 프로퍼티에 처음으로 접근하는 지점입니다.
// 이때 값이 계산되고 저장됩니다.
let items = data
print("Fetched data: \(items)")
}
}
// DataManager 인스턴스 생성
let manager = DataManager()
// fetchData() 메서드를 호출할 때 data 프로퍼티가 초기화됩니다.
manager.fetchData()
// 이미 초기화된 data 프로퍼티에 접근할 때 다시 계산하지 않습니다.
let cachedData = manager.data
지연 저장 프로퍼티를 쓸 때는 lazy라는 키워드를 프로퍼티 앞에 붙이면 됩니다.
제가 data 앞에 lazy 붙였죠? 그러면 data는 선언만 됐고 data란 변수 자체는 초기화가 되지 않은 상태입니다.
이제 제가 data라는 변수에 처음 접근 한다고 하면(소스 상에서는 func fetchData에서 처음 접근) 그제서야 data라는 변수가 초기화가 되는 것입니다.
즉, 짧게 정리하자면
위의 코드에서 data 프로퍼티는 처음으로 fetchData() 메서드에서 접근될 때 초기화됩니다. 그 이후에는 이미 초기화된 값을 사용하므로 data를 여러 번 접근해도 "Calculating data..." 메시지가 한 번만 표시됩니다.
지연 저장 프로퍼티 특징
[항상 var 키워드를 사용해야 한다]
이게 무슨 말이냐면, 상수는 인스턴스가 완전히 생성되기 전에 초기화해야 하므로 필요할 때 값을 할당하는 지연 저장 프로퍼티랑은 맞지가 않습니다. 그렇기 때문에 우리가 원하는 시점에서 초기화를 진행하기 위해서 var 키워드로 선언을 해야 한다는 것이죠.
지연 저장 프로퍼티 사용
그렇다면 지연 저장 프로퍼티는 언제 사용하는 것일까요?
지연 저장 프로퍼티는 주로 복잡한 클래스나 구조체를 구현할 때 많이 사용됩니다.
클래스 인스턴스의 저장 프로퍼티로 다른 클래스 인스턴스나 구조체 인스턴스를 할당해야 할 때가 있습니다. 이럴 때 인스턴스를 초기화 하면서 저장 프로퍼티로 쓰이는 인스턴스들이 한 번에 생성되어야 하고 굳이 모든 저장 프로퍼티를 사용할 필요가 없다면? 1, 2개라면 큰 차이가 없겠지만 몇 천, 몇 만개가 생성된다면 메모리 낭비가 굉장히 심하게 되겠죠? 그렇기 때문에 성능도 향상 시키고 메모리 낭비도 줄이기 위해 지연 저장 프로퍼티를 쓰는 것입니다!!
감사합니다.
틀린 부분이 있거나 더 좋은 내용 훈수 환영합니다!
공감과 댓글 부탁드립니다.
'Apple > Swift' 카테고리의 다른 글
[Swift] Self 프로퍼티 (2) | 2023.10.30 |
---|---|
[Swift] 객체 인스턴스(object instance) (0) | 2023.10.20 |
[Swift] 후행 클로저(trailing closure) (0) | 2023.10.18 |
[Swift] 클로저 개념 완벽 이해하기 (0) | 2023.10.17 |
[Swift] 클로저(Closure) (0) | 2023.10.16 |