[최종 수정일 : 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' 카테고리의 다른 글
Initialization (0) | 2018.09.17 |
---|---|
Inheritance (0) | 2018.08.30 |
Subscripts (0) | 2018.08.30 |
Methods (0) | 2018.08.30 |
Structures and Classes (1) | 2018.08.30 |
Enumerations (0) | 2018.08.30 |
Closures (0) | 2018.08.30 |
Functions (0) | 2018.08.30 |