Properties

Swift/Language Guide 2018.08.30 22:20

[최종 수정일 : 2018.08.28]

원문 : 애플 개발 문서 Swift 4.2 Language Guide - Properties

프로퍼티(Properties)

프로퍼티(properties)는 특정 클래스, 구조체, 열거형과 관련있는 값입니다. 저장 프로퍼티(stored properties)는 인스턴스로 상수와 변수 값을 저장하는 반면, 계산 프로퍼티(computed properties)는 값을 (저장하기 보다는)계산합니다. 계산 프로퍼티는 클래스와 구조체, 열거형에서 제공됩니다. 저장 프로퍼티는 클래스와 구조체에서만 제공됩니다.

저장(stored) 프로퍼티와 계산(computed) 프로퍼티는 일반적으로 특정 타입의 인스턴스와 관련되어 있습니다. 하지만, 프로퍼티는 타입 자체(itself)와도 관련되어 있을수도 있습니다. 이러한 프로퍼티를 타입 프로퍼티(type properties)라고 합니다.

추가적으로, 프로퍼티의 값이 변경되는 것을 감시하기 위해 프로퍼티 옵져버(observers)를 정의할 수 있으며, 사용자정의 동작으로 응답받을 수 있습니다. 프로퍼티 옵져버는 여러분이 정의한 저장 프로퍼티에 추가될수 있고, 상위클래스(superclass)로부터 상속받은 하위클래스(subclass)의 프로퍼티에도 추가될수 있습니다.

저장 프로퍼티(stored Properties)

가장 간단한 형태로, 저장 프로퍼티는 특정 클래스나 구조체의 인스턴스로 저장되는 상수나 변수 입니다. 저장 프로퍼티는 변수 저장 프로퍼티(variable stored properties)(var 키워드) 또는 상수 저장 프로퍼티(constant stored properties)(let 키워드) 중 하나 일수 있습니다.

기본 프로퍼티 값(Default Property Values)에서 설명된 것 처럼, 정의할때 저장 프로퍼티에 대한 기본 값을 제공할 수 있습니다. 초기화하는 동안 저장 프로퍼티에 대한 초기값을 설정하고 수정할 수도 있습니다. 초기화하는 동안 상수 프로퍼티 할당하기(Assigning Constant Properties During Initialization)상수 저장 프로퍼티에 대한 경우에도 가능합니다.

아래 예제는 생성된 후에는 범위의 길이를 변경할수 없는 정수형 범위를 설명하는FixedLengthRange 구조체를 정의한 것입니다.

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// the range represents integer values 0, 1, and 2
rangeOfThreeItems.firstValue = 6
// the range now represents integer values 6, 7, and 8

FixedLengthRange의 인스턴스는 변수 저장 프로퍼티 firstValue와 상수 저앞 프로퍼티 length를 가지고 있습니다. 위의 예제에서, length는 상수 프로퍼티이기 때문에, 새로운 범위가 생성될때 초기화되고 그 이후에는 변경될수 없습니다.

상수 구조체 인스턴스의 저장 프로퍼티(Stored Properties of Constant Structure Instances)

구조체의 인스턴스를 생성하고 상수에 인스턴스를 할당하는 경우에, 변수 프로퍼티로 선언되었을지라도, 인스턴스의 프로퍼티를 수정할수 없습니다.

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue = 6
// this will report an error, even though firstValue is a variable property

rangeOfFourItems가 상수(let 키워드)로 선언되었기 때문에, firstValue가 변수 프로퍼티일지라도, firstValue 프로퍼티를 변경하는 것은 불가능합니다.

이 동작은 구조체가 값 타입(value types)이기 때문입니다. 값 타입의 인스턴스가 상수로 표시될때, 모든 프로퍼티가 상수가 됩니다.

참조 타입(reference types)인 클래스에 대해서는 다릅니다. 참조 타입의 인스턴스를 상수로 할당한 경우에, 인스턴스의 변수 프로퍼티는 여전히 변경할 수 있습니다.

느린 저장 프로퍼티(Lazy Stored Properties)

느린 저장 프로퍼티(lazy stored property)는 최초 사용될때까지 초기 값이 계산되지 않는 프로퍼티 입니다. 느린 저장 프로퍼티는 선언할때 앞부분에 lazy 를 작성하여 나타냅니다.

주의
lazy 프로퍼티는 초기 값이 인스턴스 초기화가 완료될때까지는 초기 값을 가져올 수 없기 때문에, 항상 변수(let키워드)로 선언해야 합니다. 상수 프로퍼티는 항상 초기화가 완료되기 전에(before) 값을 가져야 하므로, lazy로 사용할 수 없습니다.

lazy 프로퍼티는 프로퍼티에 대한 초기 값이 외부 요인에 의해 인스턴스의 초기화가 완료될때까지 값을 알지못할때 유용합니다. lazy 프로퍼티는 필요한 경우가 아니면 그때까지 수행되어서는 안되는 복잡하거나 계산이 오래 걸리는 프로퍼티가 필요때 유용합니다.

아래 예제는 복잡한 클래스의 불필요한 초기화를 피하기 위해 lazy 저장 프로퍼티를 사용한 것입니다. 이 예제는 두개의 클래스 DataImporter과 DataManager를 정의하였고, 둘 다 전부 보여지지 않습니다.

class DataImporter {
    /*
    DataImporter is a class to import data from an external file.
    The class is assumed to take a nontrivial amount of time to initialize.
    */
    var filename = "data.txt"
    // the DataImporter class would provide data importing functionality here
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
    // the DataManager class would provide data management functionality here
}

let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// the DataImporter instance for the importer property has not yet been created

DataManager클래스는 비어있는 String 값의 배열로 초기화된 저장 프로퍼티 data를 가지고 있습니다. 비록 나머지 기능이 보이지 않지만, DataManager 클래스의 목적은 String 데이터의 배열을 관리하고 사용하는 것을 제공하기 위함입니다.

DataManager클래스의 일부 기능은 파일에서 데이터를 가져오는 것입니다. 이 기능은 DataImporter클래스에 의해 제공되며, 초기화하는데 많은 시간이 걸리는 것으로 가정합니다. DataImporter인스턴스가 초기화 될대, 파일을 열고 메모리에서 컨텐츠를 읽기 위해 DataImporter 인스턴스가 필요하기 때문일 것입니다.

DataManager 인스턴스는 파일로부터 데이터를 가져오지 않아도 데이터를 관리하는게 가능하며, DataManager 자체적으로 생성될때 새로운 DataImporter 인스턴스를 생성할 필요가 없습니다. 대신, 처음 사용할때, DataImporter 인스턴스를 만드는 것이 더 의미가 있습니다.

그것은 lazy 수식어(modifier)로 표시되며, importer프로퍼티에 대한 DataImporter인스턴스는 filename프로퍼티를 조회할때 처럼, importer 프로퍼티가 처음 사용될때에만 생성됩니다.

print(manager.importer.filename)
// the DataImporter instance for the importer property has now been created
// Prints "data.txt"

주의
lazy 수정자로 표시된 프로퍼티는 멀티 스레드에서 동시에 사용되고, 그 프로퍼티가 아직 초기화되지 않은 경우, 프로퍼티가 한번만 초기화 되는 것을 보장하지는 않습니다.

저장 프로퍼티와 인스턴스 변수(Stored Properties and Instance Variables)

Objective-C 경험이 있는 경우에, 클래스 인스턴스로 값을 저장하고 참조하는 두가지(two) 방법을 알고 있을 것입니다. 프로퍼티 외에도, 프로퍼티에 저장된 값에 대한 보조 저장소(backing store)처럼 인스턴스 변수(instance variables)를 사용할 수 있습니다.

Swift는 이러한 개념(concepts)을 하나의 프로퍼티 선언으로 통일(unifies)하였습니다. Swift 프로퍼티는 해당(corresponding) 인스턴스 변수가 없고, 프로퍼티에 대한 보조 저장소를 직접 접근(accessed)되지 않습니다. 이러한 접근법은 다른 컨텍스트(contexts)에서 값에 접근하는 방법에 대한 혼란을 피하게 하고 프로퍼티 선언을 하나의 일정한 구문으로 단순화 합니다. 프로퍼티에 대한 모든 정보(이름, 타입, 메모리 관리 특성)는 타입의 정의처럼 한 곳에서 정의됩니다.

계산 프로퍼티(Computed Properties)

저장 프로퍼티 외에도, 클래스, 구조체, 열거형에 실제 값을 저장하지 않는 계산 프로퍼티(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
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// Prints "square.origin is now at (10.0, 10.0)"

이 예제는 기하학적인(geometric) 도형으로 작업하기 위한 구조체 3개를 정의하였습니다.

  • x와 y좌표를 캡슐화한 Point
  • width와 height를 캡슐화한 Size
  • 원점과 크기로 사각형을 정의한 Rect

Rect 구조체는 계산 프로퍼티 center를 제공합니다. 현재 Rect의 중심점(center position)은 항상 origin과 size에 의해 결정되고, 명시적인 Point 값으로 중심점을 저장할 필요가 없습니다. 대신에, Rect는 사용자정의 계산 변수 center에 대한 getter과 setter를 정의하며, 실제 저장 프로퍼티 처럼 사각형의 center로 사용이 가능합니다.

위 예제에서 새로운 Rect변수 square를 생성하였습니다. square 변수는 (0, 0) 원점, 넓이와 높이는 10으로 초기화되었습니다. 이 square는 아래 그림에서 파랑색 사각형으로 표시됩니다.

square 변수의 center 프로퍼티는 현재 프로퍼티의 값을 가져오기 위해, center에 대한 getter로 호출되도록 하는 점(dot) 문법(square.center)으로 사용합니다. 기존 값을 반환하기 보다는, getter로 실제 계산하고 square의 중심을 가리키는 새로운 Point를 반환합니다. 위에서 볼수 있는 것처럼, getter은 중심점(5, 5)를 정확히 반환합니다.

center프로퍼티는 사각형을 위쪽과 오른쪽으로 이동시키는 새로운 값 (15, 15)으로 설정되며, 아래 그림에서 새로운 위치의 오렌지 사각형으로 보여집니다. center 에 대한 setter를 호출해서 center 프로퍼티를 설정하며, origin 프로퍼티에 저장된 x와 y의 값을 수정하고, 새로운 위치로 사각형을 이동시키빈다.

축약된 Setter 선언(Shorthand Setter Declaration)

계산 프로퍼티의 setter에 설정할 새로운 값에 대한 이름을 정의하지 않은 경우에, newValue라는 기본 이름이 사용됩니다. 다음은 축약 표현법(shorthand notation)의 장점을 가지는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)
        }
    }
}

읽기전용 계산 프로퍼티(Read-Only Computed Properties)

getter는 있지만 setter은 없는 계산 프로퍼티를 읽기 전용 계산 프로퍼티(read-only computed property)라고 합니다. 읽기 전용 계산 프로퍼티는 항상 값을 반환하고, 점 문법(dot syntax)으로 접근할수 있지만, 다른 값으로 설정할 수는 없습니다.

주의
값이 고정되어 있지 않기 때문에, 계산 프로퍼티는(읽기 전용 계산 프로퍼티를 포함하더라도) var 키워드를 사용하여 변수 프로퍼티로 선언해야 합니다. let 키워드는 상수 프로퍼티에 대해서만 사용되며, 인스턴스 초기화 부분에서 한번 설정되고나서 값을 변경할수 없다는 것을 나타냅니다.

get 키워드와 중괄호(braces)를 제거해서, 읽기 전용 계산 프로퍼티의 선언을 단순하게 할 수 있습니다.

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)")
// Prints "the volume of fourByFiveByTwo is 40.0"

이 예제는 3D 사각형 박스를 표현하기 위해 width, height, depth 프로퍼티로 새로운 구조체 Cuboid를 정의하였습니다. 이 구조체는 직육면체(cuboid)의 현재 volume을 계산하고 반환하는 읽기 전용 프로퍼티 volume를 가지고 있습니다. 특정 volume 값을 사용하는 width, height, depth의 값이 애매모호하기 때문에 volume에 대한 설정을 할수 없습니다. 그럼에도 불구하고, 외부 사용자가 현재 계산된 volume를 구할수 있도록 Cuboid에 대해 읽기 전용 계산 프로퍼티를 제공하는 것이 유용합니다.

프로퍼티 옵져버(Property Observers)

프로퍼티 옵져버(property observers)는 프로퍼티의 값이 변경될때 감지하고 응답합니다. 새로운 값이 프로퍼티의 현재 값과 같을지라도, 프로퍼티 옵져버는 프로퍼티의 값이 설정될때마다 호출됩니다.

lazy저장 프로퍼티만 예외이며, 정의한 모든 저장 프로퍼티에 프로퍼티 옵져버를 추가할수 있습니다. 또한, 하위 클래스에서 프로퍼티 오버라이딩(overriding)에 의해서 상속받은 프로퍼티에 프로퍼티 옵져버를 추가할 수 있습니다. 계산 프로퍼티의 setter에서 변경된 것을 감지하고 응답할수 있기 때문에, 오바라이드되지 않는(nonoverridden) 계산 프로퍼티에 대한 프로퍼티 옵져버를 정의할 필요가 없습니다. 프로퍼티 오버라이딩은 오버라이딩(Overriding)에서 설명되어 있습니다.

프로퍼티에서 이러한 옵져버를 하나 또는 둘다 정의할수 있습니다.

  • willSet은 값이 저장되기 직전에 호출됩니다.
  • didSet은 새로운 값이 저장되자마자 호출됩니다.

willSet 옵져버를 구현하는 경우, 새로운 프로퍼티 값은 상수 매개변수로 전달됩니다. willSet 구현하면서 이러한 매개변수에 대한 이름을 지정할수 있습니다. 구현하면서, 매개변수 이름과 괄호(parentheses)를 작성하지 않는 경우에, 매개변수 이름은 newValue라는 기본 매개변수 이름으로 만들어 집니다.

비슷하게, didSet 옵져버를 구현하는 경우, 예전 프로퍼티 값이 포함된 상수 매개변수가 전달 됩니다. 그 매개변수에 이름을 짓거나 기본 매개변수 이름인 oldValue를 사용할 수 있습니다. didSet옵져버에서 프로퍼티에 값을 할당하는 경우, 할당한 새 값이 방금 막 설정한 것으로 교체됩니다.

주의
상위클래스 프로퍼티의 willSet과 didSet 옵져버는 상위클래스 초기화에서 호출된 후에, 하위클래스 초기화에서 프로퍼티가 설정될때 호출됩니다. 상위클래스 초기화가 호출되기 전에, 클래스 자신의 프로퍼티를 설정하는 동안에는 호출되지 않습니다.

초기화 위임(initializer delegation)에 대한 더 자세한 내용은, 값 타입에 대한 초기화 위임(Initializer Delegation for Value Types)와 클래스 타입에 대한 초기화 위임(Initializer Delegation for Class Types)을 보세요.

다음은 willSet과 didSet동작 예제입니다. 아래 예제에서 사람이 걷는 동안에 전체 걸음수를 가져오는 새로운 클래스 StepCounter를 정의하였습니다. 이 클래스는 만보기(pedometer) 또는 다른 걸음수 측정기로 하루동안 걸음수를 추적한 데이터를 입력하여 사용할수 있습니다.

class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps

StepCounter클래스는 Int타입의 totalSteps프로퍼티를 선언합니다. 이것은 willSet과 didSet 옵져버를 사용하는 저장 프로퍼티입니다.

totalSteps에 대한 willSet과 didSet 옵져버는 프로퍼티가 새로운 값이 할당될때마다 호출됩니다. 새로운 값이 현재 값과 같을때에도 호출합니다.

이 예제의 willSet 옵져버는 새 값에 대해서 사용자정의 매개변수 이름 newTotalSteps를 사용합니다. 이 예제에서, 단순히 설정하려는 값을 출력합니다

didSet옵져버는 totalSteps가 업데이트된 후에 호출됩니다. 예전 값에 대해 새로운 totalSteps의 값과 비교합니다. 전체 걸음 수가 증가되었다면, 새로 얼마나 많이 걸었는지에 대한 메시지를 출력합니다. 그 didSet 옵져버는 예전 값(old value)에 대한 사용자정의 매개변수 이름을 제공하지 않고, 그 대신에, 기본 이름인 oldValue를 사용합니다.

주의
함수에 in-out 매개변수로 옵져버를 가지는 프로퍼티를 전달하는 경우, willSet과 didSet 옵져버는 항상 호출됩니다. in-out 매개변수에 대해 copy-in copy-out 메모리 모델이기 때문입니다. 그 값은 항상 함수의 끝에서 프로퍼티에 다시 씁니다. in-out 매개변수의 동작에 대한 자세한 내용은 In-Out 매개변수(In-Out Parameters)을 보세요.

전역 변수와 지역 변수(Global and Local Variables)

위에서 설명한 계산하고 감시(observing)하는 프로퍼티에 대한 기능은 전역 변수(global variables)와 지역 변수(local variables)에서도 사용할 수 있습니다. 전역 변수는 모든 함수, 메소드, 클로져, 타입 컨텍스트(context)의 외부에서 정의된 변수입니다. 지역변수는 함수, 메소드, 클로져 컨텍스트(closure context)안에서 정의된 변수입니다.

전역 변수와 지역 변수는 이전 챕터의 저장 변수(stored variables)에서 본적이 있습니다(encountered).. 저장 변수(stored variables)는 저장 프로퍼티처럼, 특정 타입의 값을 저장하는 공간을 제공하고 값을 설정하고 가져올수 있습니다.

또한, 전역 또는 지역 범위에서 계산 변수(computed variables)를 정의하고 저장 변수에 대한 옵져버를 정의할수 있습니다. 계산 변수는 값을 저장하는 것이 아니라 값을 계산하고, 게산 프로퍼티와 같은 방법으로 작성합니다.

주의
전역 상수와 전역 변수는 느린 저장 프로퍼티(Lazy Stored Properties)와 유사한 방식으로 항상 나중(lazily)에 계산됩니다. lazy 저장 프로퍼티와 다르게, 전역 상수와 전역 변수는 lazy 수식어 표시가 필요하지 않습니다.

지역 상수와 변수는 결코 나중(lazily)에 계산되지 않습니다.

타입 프로퍼티(Type Properties)

인스턴스 프로퍼티(Instance properties)는 특정 타입의 인스턴스에 속해있는 프로퍼티 입니다. 타입의 새로운 인스턴스를 만들때마다, 고유한 프로퍼티 값을 가지며, 다른 인스턴스와 구분됩니다.

타입 자체에 속하는 프로퍼티를 정의할 수 있으며, 타입의 어떤 한개의 인스턴스가 아닙니다. 타입의 인스턴스가 얼마나 많던지 상관없이, 이러한 프로퍼티의 복사본은 유일할 것입니다. 이러한 프로퍼티의 종류를 타입 프로퍼티(type properties)라고 부릅니다.

타입 프로퍼티는 모든 인스턴스에서 사용할 수(C언어에서 static 상수처럼) 있는 상수 프로퍼티 또는 타입의 모든 인스턴스에서 전역적으로 값을 저장하는(C언어에서 static 변수처럼) 변수 프로퍼티 처럼, 특정 타입의 모든(all) 인스턴스에서 공통적인 값을 정의하는데 유용합니다.

저장(stored) 타입 프로퍼티는 변수나 상수가 될수 있습니다. 계산(computed) 타입 프로퍼티는 계산 인스턴스 프로퍼티와 같은 방식으로, 항상 변수 프로퍼티로 선언됩니다.

주의
저장 인스턴스 프로퍼티(stored instance properties) 와 다르게, 저장 타입 프로퍼티는 항상 기본값을 제공해야합니다. 초기화 시점에 타입 스스로 저장 타입 프로퍼티에 값을 할당하는 초기화가 없기 때문입니다.

저장 타입 프로퍼티(stored type properties) 는 처읍 접근할때 나중(lazily)에 초기화됩니다. 멀티 스레트 환경에서 접근할때에도 한번만 초기화되는 것을 보장하고, lazy 수식어를 표시할 필요가 없습니다.

타입 프로퍼티 문법(Type Property Syntax)

C와 Objective-C에서는, 전역(global) static 변수로 타입과 관련된 static 상수와 변수를 정의합니다. 하지만 Swift에서는, 타입 프로퍼티는 
타입의 바깥쪽 중괄호(curly braces)에서 타입의 정의로 작성하고, 각 타입 프로퍼티는 타입이 지원하는 명시적인 범위가 지정됩니다.

static 키워드로 타입 프로퍼티를 정의합니다. 클래스 타입에 대한 계산 타입 프로퍼티(computed type properties)에 대해서, 상위 클래스 구현을 오버라이드하는것을 하위클래스에서 허용하기 위해 class 키워드를 사용할수 있습니다. 아래 예제는 저장 타입 프로퍼티(stored type properties)와 계산 타입 프로퍼티(computed type properties)에 대한 문접을 보여줍니다.

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

주의
위의 계산 타입 프로퍼티(computed type property) 예제는 읽기 전용 계산 타입프로퍼티(read-only computed type properties) 이지만, 계산 인스턴스 프로퍼티와 동일한 문법으로 읽기 쓰기 계산 타입 프로퍼티(read-write computed type properties)를 정의할 수 있습니다.

타입 프로퍼티 조회하고 설정하기(Querying and Setting Type Properties)

타입 프로퍼티는 인스턴스 프로퍼티 처럼, 점 문법(dot syntax)으로로 조회하고 설정합니다. 하지만, 타입 프로퍼티는 타입의 인스턴가 아닌 타입(type)에서 조회하고 설정합니다. 예를 들어:

print(SomeStructure.storedTypeProperty)
// Prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// Prints "Another value."
print(SomeEnumeration.computedTypeProperty)
// Prints "6"
print(SomeClass.computedTypeProperty)
// Prints "27"

다음에 오는 예제는 오디오 채널의 갯수에 대한 오디오 레벨미터(level meter)를 모델링한 구조체에서 두개의 저장 타입 프로퍼티를 사용합니다. 각 채널은 0부터 10까지 포함한(inclusive) 정수형 오디오 레벨을 가집니다.

아래 그림은 스테레오 오디오 레벨 미터를 모델링하기 위해 두개의 오디오 채널을 결합하는 방법을 보여줍니다. 채널의 오디오 레벨이 0일때, 그 채널에 대해 켜져있는 조명이 아무것도 없습니다. 오디오 레벨이 10일때, 그 채널에 대해 모든 조명이 켜져있습니다. 그림에서, 왼족 채널은 9레벨이고, 오른족 채널은 7레벨 입니다.

위에서 설명한 오디오 채널은 AudioChannel 구조체의 인스턴스로 표현됩니다.

struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
        didSet {
            if currentLevel > AudioChannel.thresholdLevel {
                // cap the new audio level to the threshold level
                currentLevel = AudioChannel.thresholdLevel
            }
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                // store this as the new overall maximum input level
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
        }
    }
}

AudioChannel 구조체는 그 기능을 지원하기 위해 두개의 저장 타입 프로퍼티를 정의 합니다. 첫번째로, thresholdLevel이며, 오디오 레벨이 가질수 있는 최대 임계 값(threshold value)을 정의합니다. 이것은 모든 AudioChannel인스턴스에 대한 상수값 10 입니다. 오디오 신호가 10보다 높은 값이 들어오면, (아래 설명된 것처럼) 임계 값에 의해 제한(capped) 될 것입니다.

두번째 타입 프로퍼티는 변수 저장 프로퍼티 maxInputLevelForAllChannels입니다. 이것은 모든(any) AudioChannel 인스턴스에서 받은 최대 입력 값을 유지합니다.그것은 초기 값 0으로 시작합니다.

또한, AudioChannel 구조체는 0에서 10까지의 눈금(scale)으로 채널의 현재 오디오 레벨을 표현하는 저장 인스턴스 프로퍼티 currentLevel을 정의합니다.

currentLevel 프로퍼티는 currentLeve의 값이 설정될때마다 확인하기 위한 didSet프로퍼티 옵져버를 가지고 있습니다. 이 옵져버는 두 가지를 검사(check)합니다.

  • currentLevel의 새로운 값이 thresholdLevel보다 더 크면, 그 프로퍼티 옵져버는 currentLevel을 thresholdLevel로 제한합니다.
  • currentLevel의 새로운 값이 이전에 어떤 AudioChannae인스턴스로 부터 받은 값보다 크면, 프로퍼티 옵져버는 새로운 currentLevel 값을 maxInputLevelForAllChannels 타입 프로퍼티에 저장합니다.

주의
두가지 검사중 첫번째에서, didSet옵져버는 currentLevel을 다른 값으로 설정합니다. 하지만, 그 옵져버가 다시 호출되지는 않습니다.

스테레오 사은드 시스템의 오디오 레벨을 표현하기 위해, AudioChannel구조체를 사용해서 두개의 새로운 오디오 채널 leftChannel과 reightChannel을 만들수 있습니다.

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

왼쪽(left) 채널의 currentLevel을 7로 설정하는 경우, maxInputLevelForAllChannels 타입 프로퍼티가 7로 업데이트 되는 것을 볼수 있습니다.

leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// Prints "7"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "7"

오른족(right) 채널의 currentLevel을 11로 설정하는 경우, 오른족 채널의 currentLevel 프로퍼티가 최대 값 10으로 제한되고, maxInputLevelForAllChannel 타입 프로퍼티가 10으로 업데이트 되는 것을 볼수 있습니다.

rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// Prints "10"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "10"


'Swift > Language Guide' 카테고리의 다른 글

Subscripts  (0) 2018.08.30
Methods  (0) 2018.08.30
Properties  (0) 2018.08.30
Structures and Classes  (0) 2018.08.30
Enumerations  (0) 2018.08.30
Closures  (0) 2018.08.30
Posted by 까칠코더