프로퍼티
프로퍼티는 값에 대한 저장 여부를 기준으로 저장 프로퍼티, 연산 프로퍼티로 나뉜다. 소속에 따른 기준으로 인스턴스 프로퍼티, 타입 프로퍼티로 나뉜다.
저장 프로퍼티
- 일반적인 변수 혹은 상수가 저장 프로퍼티에 해당한다.
- 저장 프로퍼티는 입력된 값을 저장하거나 저장된 값을 제공하는 역할을 한다.
- 변수 및 상수를 통해 정의 가능하다.
- 클래스와 구조체에서는 사용이 가능하지만 열거형에서는 사용이 불가하다.
- 변수 혹은 상수 키워드 앞에 lazy를 붙이면 프로퍼티가 사용되는 시점에서야 프로퍼티가 초기화된다. (일반적인 경우 인스턴스가 생성됨과 동시에 모든 프로퍼티도 초기화된다.)
- 저장 프로퍼티중에서는 로직이나 연산을 통한 값을 저장해야할 경우가 있는데, 이와 같은 경우에 클로저를 사용한다.
- 연산 프로퍼티와 비슷하지만, 처음 프로퍼티가 생성될 때 단 한 번만 값을 평가한다.
class Exam {
var property = { () -> Void in //클로저를 이용한 변수 생성
print("생성")
}()
}
var exam: Exam = Exam() //"생성" 출력
exam.property //아무런 일도 일어나지 않음
연산 프로퍼티
- 특정 연산을 통해 값을 만들어 제공한다.
- 변수만 사용이 가능하다.
- 클래스, 구조체, 열거형에서 모두 사용이 가능하다.
- 연산 프로퍼티의 값을 참조하기 위해서는 get 구문을 사용한다.
- 연산 프로퍼티에 set 구문을 추가하면 값을 할당하거나 변경할 수 있다.
- get은 연산 프로퍼티가 값을 반환하는 기능을 하기 위해서 필수이며, set은 선택적이다.
- get 구문만 있다면 get 키워드는 생략이 가능하다.
class Plus {
var num1: Int = 1
var num2: Int = 2
var result: String = "안녕"
var num3: String {
get {
return result
}
set(newNum) {
result = String(Int(newNum)! + self.num1 + self.num2)
}
}
}
var plus = Plus()
plus.num3 //안녕
plus.num3 = "10"
plus.result //13
일종의 함수적인 역할을 하는 연산 프로퍼티는 프로퍼티이기는 하지만 다른 프로퍼티와의 관계가 의존적인 경우에 사용한다. 예를 들면 도형의 중심 좌표는 도형의 기준 좌표 x, y와 가로, 세로 길이에 의존적이기 때문에 저장 프로퍼티보다는 연산 프로퍼티로 쓰이는 것이 훨씬 합당하다. 물론 저장 프로퍼티를 쓸 수 있지만 연산 프로퍼티는 자동적으로 이 관계속에서 계산을 할 수 있어 코드의 반복을 줄일 수 있다.
프로퍼티 옵저버
프로퍼티 옵저버란 프로퍼티의 상태를 지속적으로 관찰하여 값이 변하였거나, 변할경우 각각 이전의 값, 미래의 값을 전달하는 기능을 한다.
didSet, willSet 구문으로 사용 가능하다.
struct StudentA {
var score: Int = 93 {
didSet {
print("중간고사 점수가 \(oldValue)점으로부터 \(score)점으로 바뀌었습니다.")
}
willSet {
print("기말고사 점수는 \(score)점으로부터 \(newValue)점까지 올릴 계획입니다.")
}
}
}
var studentA: StudentA = StudentA()
studentA.score = 80 //중간고사 점수가 93점으로부터 80점으로 바뀌었습니다. 기말고사 점수는 80점으로부터 93점까지 올릴 계획입니다.
didSet과 willSet은 항상 같이 사용되어야 하는 것은 아니다.
선택적으로 사용하되, 프로퍼티 변화에 따라 쓰임새를 정확히 해야한다.
타입 프로퍼티
앞서 배운 프로퍼티는 인스턴스를 생성한 후에 사용해야 하기에 인스턴스 프로퍼티이다. 반면 타입 프로퍼티는 인스턴스를 만들지 않고 클래스나 구조체 자체에 저장되며, 모든 인스턴스가 사용이 가능한 것을 타입 프로퍼티라 한다. 인스턴스 프로퍼티는 인스턴스마다 개별 프로퍼티를 가지지만, 타입 프로퍼티는 모든 인스턴스가 하나의 값을 가진다.
타입 프로퍼티는 변수나 상수를 선언하는 키워드 var or let 앞에 static 키워드를 붙인다.
타입 프로퍼티로 선언된 변수가 연산 프로퍼티일 경우 static 대신 class 키워드를 사용하면 하위 클래스에서도 사용이 가능한 타입 프로퍼티로 정의할 수 있다. (클래스에서만 사용 가능)
타입 프로퍼티는 선언과 동시에 초기값을 반드시 지정해야만 한다. (인스턴스와 상관이 없기 때문에 초기화 과정에서 값을 할당할 수 없기 때문이다.)
class Apple {
class var apple: Int { //타입 프로퍼티로 선언된 연산 프로퍼티
return 100
}
}
Apple.apple //100
struct Banana {
static var banana: Int = 3 //타입 프로퍼티로 선언된 저장 프로퍼티
}
Banana.banana //3
이처럼 static, class 키워드를 사용한 타입 프로퍼티의 경우는 인스턴스의 생성없이 바로 사용이 가능하다.