🔥 계산 속성

736자
8분

저장 속성 외에도 클래스, 구조체 그리고 열거형은 계산 속성(computed properties)을 정의할 수 있습니다. 계산 속성은 실제로 값을 저장하지 않아요. 대신에 다른 속성이나 값을 간접적으로 검색하고 설정하기 위해 getter와 선택적인 setter를 제공하지요.

예를 들어 볼까요?

struct Point {
    var x = 0.0, y = 0.0
}
 
struct Size {
    var width = 0.0, height = 0.0
}
 
struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}
 
var square = Rect(origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
// initialSquareCenter는 (5.0, 5.0)
 
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// "square.origin is now at (10.0, 10.0)"를 출력합니다.
 
swift

이 예제는 기하학적 도형을 다루기 위한 세 개의 구조체를 정의하고 있어요.

  • Point는 점의 x, y 좌표를 캡슐화합니다.
  • Sizewidthheight를 캡슐화하고요.
  • Rect는 원점(origin point)과 크기(size)로 사각형을 정의하네요.

Rect 구조체는 center라는 계산 속성도 제공해요. Rect의 현재 중심 위치는 항상 originsize로부터 결정될 수 있기에, 중심점을 명시적인 Point 값으로 저장할 필요가 없습니다. 대신 Rectcenter라는 연산 변수에 대한 사용자 정의 getter와 setter를 정의하여, 마치 실제 저장 속성인 것처럼 사각형의 center로 작업할 수 있도록 해주지요.

위의 예제는 square라는 새로운 Rect 변수를 생성합니다. square 변수는 원점이 (0, 0)이고, 너비와 높이가 10인 값으로 초기화되요. 이 정사각형은 아래 다이어그램에서 연한 녹색 정사각형으로 표현됩니다.

lecture image

그런 다음 점 문법(square.center)을 통해 square 변수의 center 속성에 접근하는데, 이는 현재 속성 값을 검색하기 위해 center의 getter를 호출하게 됩니다. 기존 값을 반환하는 대신, getter는 실제로 정사각형의 중심을 나타내는 새로운 Point를 계산하고 반환하네요. 위에서 볼 수 있듯이 getter는 (5, 5)의 중심점을 정확히 반환하고 있어요.

그 후에 center 속성을 (15, 15)의 새 값으로 설정하면, 정사각형이 위 다이어그램의 진한 녹색 정사각형으로 표시된 새 위치로 위쪽과 오른쪽으로 이동하게 됩니다. center 속성을 설정하면 center의 setter가 호출되어 저장된 origin 속성의 xy 값을 수정하고 정사각형을 새 위치로 이동시키지요.

단축 Setter 선언

만약 계산 속성의 setter가 설정될 새 값에 대한 이름을 정의하지 않는다면, 기본 이름인 newValue가 사용됩니다. 이 단축 표기법을 활용한 Rect 구조체의 대안 버전을 살펴볼까요?

struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}
swift

단축 Getter 선언

만약 getter의 전체 본문이 단일 표현식이라면, getter는 암시적으로 해당 표현식을 반환합니다. 이 단축 표기법과 setter의 단축 표기법을 활용한 Rect 구조체의 또 다른 버전을 보시죠.

struct CompactRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            Point(x: origin.x + (size.width / 2),
                  y: origin.y + (size.height / 2))
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}
swift

getter에서 return을 생략하는 것은 Functions With an Implicit Return에 설명된 대로 함수에서 return을 생략하는 것과 동일한 규칙을 따릅니다.

읽기 전용 계산 속성

getter는 있지만 setter가 없는 계산 속성을 읽기 전용 계산 속성라고 합니다. 읽기 전용 계산 속성은 항상 값을 반환하며, 점 문법을 통해 접근할 수 있지만 다른 값으로 설정할 수는 없어요.

get 키워드와 그 중괄호를 제거하여 읽기 전용 계산 속성의 선언을 단순화할 수 있답니다.

struct Cuboid {
    var width = 0.0, height = 0.0, depth = 0.0
    var volume: Double {
        return width * height * depth
    }
}
 
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// "the volume of fourByFiveByTwo is 40.0"를 출력합니다.
swift

이 예제는 Cuboid라는 새로운 구조체를 정의하는데, 이는 width, height, depth 속성을 가진 3D 직사각형 상자를 나타냅니다. 이 구조체는 또한 volume이라는 읽기 전용 계산 속성을 가지고 있어요. 이는 cuboid의 현재 부피를 계산하고 반환하지요.

volume을 설정 가능하게 만드는 것은 어떤 width, height, depth 값이 특정 volume 값에 사용되어야 하는지 모호하기 때문에 의미가 없어요. 그럼에도 불구하고 외부 사용자가 현재 계산된 부피를 알 수 있도록 Cuboid가 읽기 전용 계산 속성을 제공하는 것은 유용하답니다.

이렇게 계산 속성은 실제로 값을 저장하지 않으면서도 다른 속성의 값에 기반하여 동적으로 계산된 값을 제공할 수 있게 해줍니다. 이는 코드의 가독성을 높이고 중복을 줄이는 데 큰 도움이 되지요. 계산 속성을 적절히 활용한다면 Swift 코드를 더욱 간결하고 표현력 있게 만들 수 있을 거예요!