인스턴스 또는 타입의 부분인 저장된 값과 계산된 값에 접근한다.
프로퍼티 (Properties) 는 값을 특정 클래스, 구조체, 또는 열거형에 연결한다. 저장된 프로퍼티 (Stored properties)는 인스턴스의 일부로 상수와 변수 값을 저장하는 반면에 계산된 프로퍼티 (computed properties)는 값을 저장하는 대신에 계산한다. 계산된 프로퍼티 (Computed properties)는 클래스, 구조체, 그리고 열거형에 의해 제공된다. 저장된 프로퍼티는 클래스와 구조체에 의해서만 제공된다.
저장된 프로퍼티와 계산된 프로퍼티는 대게 특정 타입의 인스턴스와 연결된다. 그러나 프로퍼티는 타입 자체와도 연결될 수 있다. 이러한 프로퍼티를 타입 프로퍼티라 한다.
또한 프로퍼티 관찰자 (property observers)를 정의하여 프로퍼티의 값이 변경되는 것을 모니터링 하고 사용자 지정 동작에 응답할 수 있다. 프로퍼티 관찰자는 직접 정의한 저장된 프로퍼티와 하위 클래스가 수퍼 클래스에서 상속하는 프로퍼티에 추가될 수 있다.
프로퍼티 래퍼를 사용하여 여러 프로퍼티의 getter와 setter에서 코드를 재사용 할 수 있다.
가장 간단한 형식으로 저장된 프로퍼티는 특정 클래스 또는 구조체의 인스턴스의 멤버로 저장된 상수 또는 변수이다. 저장된 프로퍼티는 저장된 프로퍼티 변수 (variable stored properties) (var 키워드 사용) 또는 저장된 프로퍼티 상수 (constant stored properties) (let 키워드 사용)로 쓸 수 있다.
정의의 부분으로 저장된 프로퍼티에 대한 기본값을 제공할 수 있다. 초기화 중에 저장된 프로퍼티에 초기값을 설정하고 수정할 수도 있다. 상수 저장 프로퍼티도 마찬가지이다.
아래 예제는 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 는 새 범위가 생성될 때 초기화되며 프로퍼티 상수 이므로 변경할 수 없다.
구조체의 인스턴스를 생성하고 상수로 할당하면 프로퍼티 변수로 선언되어 있어도 인스턴스의 프로퍼티를 수정할 수 없다:
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 프로퍼티를 변경할 수 없다.
이러한 동작은 구조체가 값 타입 이기 때문이다. 값 타입의 인스턴스를 상수로 선언하면 인스턴스의 모든 프로퍼티에 대해 수정할 수 없다.
클래스는 참조 타입이므로 다르게 동작한다. 참조 타입의 인스턴스를 상수로 할당하면 인스턴스의 프로퍼티 변수는 변경할 수 있다.
지연 저장된 프로퍼티 (lazy stored property) 는 처음 사용될 때 까지 초기값이 계산되지 않는 프로퍼티이다. 지연 저장된 프로퍼티는 선언 전에 lazy 수정자를 붙여 나타낸다.
Note
인스턴스 초기화가 완료된 후에도 초기값이 없을 수 있으므로 지연 프로퍼티는 var 키워드를 사용하여 변수로 선언해야 한다. 프로퍼티 상수는 초기화가 완료되기 전에 항상 값을 가지고 있어야 하므로 lazy로 선언할 수 없다.
지연 프로퍼티는 인스턴스의 초기화가 완료될 때까지 값을 알 수 없는 외부 요인에 인해 초기값이 달라질 때 유용하다. 지연 프로퍼티는 프로퍼티의 초기값으로 필요할 때까지 수행하면 안 되는 복잡하거나 계산 비용이 많이 드는 경우에도 유용하다.
아래의 예제는 복잡한 클래스에 불필요한 초기화를 피하기 위해 지연 저장된 프로퍼티를 사용한다. 이 예제는 DataImporter 와 DataManager 라는 2개의 클래스를 정의한다:
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 수식어가 붙어 있으므로 importer 프로퍼티의 DataImporter 인스턴스는 filename 프로퍼티를 조회할 때처럼 importer 프로퍼티에 처음 접근될 때 생성된다:
print(manager.importer.filename)
// the DataImporter instance for the importer property has now been created
// Prints "data.txt"
Note
lazy 수식어가 표시된 프로퍼티는 여러 쓰레드에서 동시에 접근되고 프로퍼티가 아직 초기화되지 않은 경우 프로퍼티가 한번만 초기화된다는 보장이 없다.저장된 프로퍼티와 인스턴스 변수 (Stored Properties and Instance Variables)
Objective-C에 경험이 있다면 클래스 인스턴스의 일부로 값과 참조를 저장하는 2가지 방법을 제공한다는 것을 알 수 있다. 프로퍼티 외에도 프로퍼티에 저장된 값을 백업 저장소로 인스턴스 변수를 사용할 수 있다.
Swift는 단일 프로퍼티 선언으로 개념을 통합한다. Swift 프로퍼티는 해당 인스턴스 변수가 없으며 프로퍼티에 백업 저장소에 직접적으로 접근할 수 없다. 이 접근 방식은 다른 컨텍스트에서 값에 접근하는 것에 대한 혼동을 피할 수 있으며 프로퍼티 선언을 하나의 명확한 구문으로 단순화한다. 이름, 타입, 그리고 메모리 관리, 특성을 포함한 프로퍼티에 대한 모든 정보는 타입의 정의에 부분으로 한곳에서 정의된다.