스위프트에선 앞서 소개한 저장프로퍼티 외에 연산 프로퍼티를 정의하여 사용할 수 있다. 연산 프로퍼티(computed property)는 필요한 값을 제공한다는 점에서 저장 프로퍼티와 같지만, 실제 값을 저장했다가 반환하지는 않고 다른 프로퍼티의 값을 연산처리한 후 간접적으로 값을 제공한다.
이 때 프로퍼티의 값을 참조하기 위해 내부적으로 사용하는 구문이 get 구문이다. 함수와 비슷해 내부적으로 return 키워드를 사용해 값을 반환하는데, 여기서 반환되는 값이 프로퍼티가 제공하는 값이된다.
또한, 연산 프로퍼티는 선택적으로 set 구문을 추가할 수도 있다. 이는 연산 프로퍼티에 값을 할당하거나 변경하고자 할 때 실행되는 구문이다. 연산 프로퍼티 자체가 값을 저장하지 않기 때문에 이 때 할당되는 값은 연산의 중요한 요소로 사용되며 set 구문은 필요에 따라 연산 프로퍼티에서 생략도 가능하다. set 구문이 생략되면 외부에서 연산 프로퍼티에 값을 할당할 수 없으며, 내부적인 연산처리를 통해 값을 제공하는 읽기 전용 프로퍼티가 만들어진다.
하지만 get 구문은 연산 프로퍼티에서 필수 요소이다. get 구문이 생략된다면 연산프로퍼티가 값을 반환하는 기능 자체를 갖지 못하기 때문이다.
연산 프로퍼티의 정의 형식은 저장 프로퍼티의 형식과 많이 다르다. 함수와 조금 비슷한 모양을 가지고 있다. 또한 연산 프로퍼티는 항상 클래스, 구조체, 열거형 내부에서만 사용이 가능하다.
class/struct/enum 객체명 {
...
var 프로퍼티명 : 타입 {
get {
필요한 연산 과정
return 반환값
}
set(매개변수명) {
필요한 연산구문
}
}
}
기본 형식은 이와 같다. 연산 프로퍼티의 경우 다른 프로퍼티에 의존적이거나, 특정 연산을 통해 얻을 수 있는 값을 정의할 때 사용된다. 다음 예제는 연산 프로퍼티를 사용해 나이를 계산하는 예제이다.
import Foundation
struct UserInfo {
// 저장 프로퍼티 : 태어난 연도
var birth: Int!
// 연산 프로퍼티 : 올해가 몇년도인지 계산
var thisYear: Int! {
get {
let df = DateFormatter()
df.dateFormat = "yyyy"
return Int(df.string(from: Date()))
}
}
// 연산 프로퍼티 : 올해 - 태어난 연도 + 1
var age: Int {
get {
return (self.thisYear - self.birth) + 1
}
}
}
let info = UserInfo(birth: 1997)
print(info.age)
/* 실행결과
26
더 복잡한 예제를 다뤄보자. 연산 프로퍼티를 사용해 사각형의 중심 좌표를 구하는 예제이다.
struct Position {
var x: Double = 0.0
var y: Double = 0.0
}
struct Size {
var width: Double = 0.0
var height: Double = 0.0
}
struct Rect {
// 사각형이 위치한 기준 좌표 (좌측 상단)
var origin = Position()
// 가로 세로 길이
var size = Size()
// 사각형의 X좌표 중심
var center: Position {
get {
let centerX = self.origin.x + (self.size.width / 2)
let centerY = self.origin.y + (self.size.height / 2)
return Position(x: centerX, y: centerY)
}
set(newCenter) {
self.origin.x = newCenter.x - (size.width / 2)
self.origin.y = newCenter.y - (size.height / 2)
}
}
}
let p = Position(x: 0.0, y: 0.0)
let s = Size(width: 10.0, height: 10.0)
var square = Rect(origin: p, size: s)
print("square.centerX = \(square.center.x), square.centerY = \(square.center.y)")
/* 실행결과
square.centerX = 5.0, square.centerY = 5.0
연산 프로퍼티의 set 구문은 활용하기에 따라 다른 저장 프로퍼티의 값을 변경하는데도 사용할 수 있다. 중심 좌표의 경우 원래 위치 좌표나 가로 세로 길이에 영향을 받아 결정되는 의존 속성이나, 중심 좌표를 옮김으로 기준 좌표의 위치가 이동할 수도 있는 것이다. 그래서 이 같은 내용을 center 프로퍼티의 set 구문에 정의했다.
center 프로퍼티의 set 구문을 살펴보자. 연산 프로퍼티에 값을 할당하면 여기에 정의된 구문이 실행된다. 프로퍼티에 할당된 값은 set 다음에 오는 괄호의 인자값으로 전달되는데, 이 때 인자값의 참조를 위해 매개변수가 사용된다. 위 예제에선 newCenter가 매개변수의 이름인 것이다. 만약 매개변수명이 생략된다면 'newValue'라는 기본 인자명이 사용된다.
다소 의아한점 이 있을 것이다. 왜냐하면 매개변수만 있고 타입이 없기 때문이다. 이는 연산 프로퍼티에 할당할 수 있는 값의 타입이 앞에서 이미 정의되어있기 때문이다. 어차피 입력할 수 있는 타입은 연산 프로퍼티의 타입으로 정해져 있기 때문에, 매개변수에는 타입을 생략할 수 있는 것이다.
중심 좌표의 값을 변경해보자. 일반 프로퍼티에 값을 넣는 것처럼 바꿀 중심 좌표를 적절하게 다음과 같이 넣어주면 된다.
square.center = Position(x: 20.0, y: 20.0)
print("square.x = \(square.origin.x), square.y = \(square.origin.y)")
/* 실행결과
square.x = 15.0, square.y = 15.0
연산 프로퍼티에 center에 값을 할당하고 있다. Position(x: 20.0, y: 20.0)은 Position 구조체로 정의된 인스턴스이다. 중심 좌표를 (20, 20)으로하는 값을 가지는 좌표 구조체이다. 이 값을 할당하면 set 구문이 실행되어 위와 같은 결과값을 출력한다.
이러한 경우가 때론 방지되어야 할 때가 있다. 또 다른 대표적인 연산 프로퍼티의 예가 바로 배열의 크기를 알려주는 count인데, count 프로퍼티는 실제로 배열에 들어간 아이템의 개수와 같아야한다. 하지만 배열에 아이템을 추가하지 않고 실수로 count의 값을 늘려버릴 수도 있는 것이다. 이 때 우리는 배열의 count프로퍼티를 사용자가 임의로 수정할 수 없도록 해야한다.
이를 위해선 set 구문을 제거하면된다. set 구문이 정의되어 있지 않으면 프로퍼티를 통해 값을 읽기만 할 뿐 할당은 할 수 없기 때문이다. 이처럼 읽기만 가능하고 쓰기는 불가능한 프로퍼티를 read-only 프로퍼티, 또는 get-only 프로퍼티라고 하고 우리말로 읽기 전용 프로퍼티라고 한다.
// 읽기 전용 (Read-Only) 속성으로 정의된 center 프로퍼티
var center: Position {
get {
let centerX = self.origin.x + (self.size.width / 2)
let centerY = self.origin.y + (self.size.height / 2)
return Position(x: centerX, y: centerY)
}
}
출처 : 꼼꼼한 재은씨의 Swift 문법편
'Swift > 문법' 카테고리의 다른 글
스위프트(Swift) - Raw String (0) | 2022.07.13 |
---|---|
스위프트(Swift) - 구조체와 클래스 Ⅱ. 프로퍼티 - 저장프로퍼티 (0) | 2022.06.01 |
스위프트(Swift) - 구조체와 클래스 Ⅰ. 기본 개념 (0) | 2022.05.31 |
스위프트(Swift) - 함수(Fuction) Ⅹ. @escaping, @autoescape (0) | 2022.05.26 |
스위프트(Swift) - 함수(Function) Ⅸ. 트레일링 클로저(Trailing Closure) (0) | 2022.05.25 |