1. Properties
- Properties 은 클래스, 구조체, 열거형과 관련된 값입니다. 특성의 종류에는 Stored Properties와 Computed Properties가 있습니다.
- Stored Properties 은 값을 저장하고 있는 프로퍼티이며, Computed Properties 은 값을 저장하고 있지 않고 특정하게 계산한 값을 반환해 주는 프로퍼티입니다.
- Computed Properties 은 클래스, 구조체, 열거형 모두에서 사용 가능하지만, Stored Properties 은 클래스와 구조체에서만 사용 가능하며 프로퍼티 옵서버를 정의해서 값이 변할 때마다 모니터링할 수 있습니다.
2. Stored Properties
- Stored Properties는 위에서 설명한 대로 단순히 값을 저장하고 있는 프로퍼티입니다. 이 프로퍼티는 let(상수) 및 var(변수)로 선언하여 사용할 수 있습니다.
<swift />
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
- 위 예제를 보면 firstValue와 lengthlength에 첫 값과 그 길이를 각각의 프로퍼티에 저장해 범위 값을 표현합니다.
3. Stored Properties of Constant Structure Instances
- 구조체를 상수로 선언하면 구조체 인스턴스의 프로퍼티를 변경할 수 없습니다.
<swift />
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 let으로 선언하더라도 프로퍼티를 변경 가능합니다. 왜냐하면 클래스 인스턴스는 참조 타입 이기 때문입니다.
4. Lazy Stored Properties
- Lazy Stored Properties는 값이 처음으로 사용되기 전에는 계산되지 않는 프로퍼티입니다. Lazy Stored Properties로 선언하기 위해서는 프로퍼티의 선언 앞에 lazy 키워드를 붙이면 됩니다.
- Lazy Stored Properties는 반드시 변수로 선언해야 합니다. 왜냐하면 상수는 초기화가 되기 전에 항상 값을 같은 property인데, 지연 프로퍼티는 처음 사용되기 전에는 값을 갖지 않는 프로퍼티이기 때문입니다.
<swift />
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 hasn't yet been created
- DataManager라는 클래스를 선언하고 이 클래스는 데이터를 가져오는 DataImporter클래스를 갖고 있습니다. 그리고 이 DataImporter는 실제 디스크 파일에서 데이터를 가져오기 때문에 초기화에 많은 시간이 걸립니다.
- 그러므로 이 클래스를 지연 프로퍼티(lazy var importer = DataImporter()) 로 선언해야 합니다.
- 이 프로퍼티는 코드에서 볼 수 있듯 DataManager 인스턴스 manager를 생성하고 거기에 data를 넣어도 그 시점에 DataImporter인스턴스는 생성되어 있지 않습니다. 지연 프로퍼티로 선언해 놓았기 때문에 실제 그 프로퍼티를 사용하기 전에는 복잡하고 시간 이 많이 필요로 하는 연산을 할 필요가 없습니다.
<swift />
print(manager.importer.filename)
// the DataImporter instance for the importer property has now been created
// Prints "data.txt"
- manager.importer.filename가 실행되어 실제로 importer 프로퍼티에 처음 접근할 때 importer 인스턴스는 생성됩니다.
5. Computed Properties
- Stored Properties 뿐만 아니라 추가적으로 클래스, 구조체, 열거형은 Computed Properties를 선언할 수 있습니다. 이 Computed Properties는 실제 값을 저장하고 있는 것이 아니라 getter와 optional 한 setter를 제공해 값을 탐색하고 간접적으로 다른 프로퍼티 값을 설정할 수 있는 방법을 제공합니다.
<swift />
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)"
- 위 코드는 좌표와 크기를 갖는 사각형을 표현하는 구조체에 관한 코드입니다.
- 여기서 Rect 구조체는 사각형의 중점을 표현하는 center center라는 계산된 프로퍼티를 제공합니다.
- 이 프로퍼티는 계산된 프로퍼티의 정의대로 값을 직접 갖고 있는 것이 아니라 다른 좌표와 크기 프로퍼티들을 적절히 연산해서 구할 수 있습니다.
- setset으로 사각형의 중점을 직접 설정할 수 있는데, 이 값을 설정할 때 x, y좌표가 어떤 값을 가져야 하는지 계산해서 x, y에 적절한 좌표값을 넣어 줍니다.

6. Shorthand Setter Declaration
- Setter의 인자 이름을 아래와 같이 set(newCenter)라고 명시했지만, 만약 이렇게 (newCenter)라고 인자 이름을 지정하지 않으면 인자 기본 이름인 newValue를 사용할 수 있습니다.
<swift />
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)
}
}
}
- set메서드 안에서 인자 이름을 지정하지 않았는데도 newValue.x, newValue.y를 사용 가능한 것을 확인할 수 있습니다.
7. Read-Only Computed Properties
- getter만 있고 setter를 제공하지 않는 계산된 프로퍼티를 Read-Only Computed Properties라고 합니다.
- Read-Only Computed Properties는 반드시 반환 값을 제공하고 다른 값을 지정할 수는 없는 프로퍼티입니다.
- 계산된 프로퍼티를 선언 시에는 반드시 상수가 아니라 변수로 선언해야 합니다.
- 보통 읽기 전용(read-only)이라 함은 한번 값이 정해지면 변하지 않기 때문에 상수로 선언하는 것이 맞으나 계산된 프로퍼티는 읽기 전용(read-only)이라 하더라도 계산 값에 따라 값이 변할 수 있기 때문에 변수로 선언합니다.
- volume이라는
<swift />
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"
8. Property Observers
- 프로퍼티에는 새 값이 set 될 때마다 이벤트를 감지할 수 있는 옵서버를 제공합니다. 이것을 Property Observers 라 하는데 Property Observers는 새 값이 이전 값과 같더라도 항상 호출됩니다.
- Property Observers는 Lazy Stored Properties에서는 사용할 수 없습니다.
- 서브클래스의 프로퍼티에 옵서버를 정의하는 것이 가능합니다.
- Computed Properties에서는 setter 값의 변화를 감지할 수 있어서 옵서버를 정의할 필요가 없습니다.
- 프로퍼티에서는 2가지의 옵서버를 제공합니다.
1. willSet : 값이 저장되기 바로 직전에 호출
- willSet에서는 newValue를 사용합니다.
2. didSet : 새 값이 저장되고 난 직후에 호출
- didSet에서는 oldValue를 사용합니다.
- 서브클래스에서 특정 프로퍼티의 값을 설정했을 때, 슈퍼클래스의 초기자가 호출된 후 willSet, didSet 프로퍼티 옵서버가 실행됩니다. 슈퍼클래스에서 프로퍼티를 변경하는 것도 마찬가지로 슈퍼클래스의 초기자가 호출된 후 옵서버가 실행됩니다. 아래는 Property Observers의 예시입니다.
<swift />
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
- 만약 in-out 파라미터로 선언된 함수의 인자에 프로퍼티를 넘기면 willSet 및 didSet이 항상 실행됩니다. 이유는 in-out 파라미터이기 때문에 프로퍼티가 항상 복사되기 때문입니다. 이 in-out 파라미터의 프로퍼티는 항상 원래 값에 새 값을 다시 덮어쓰게 됩니다.
9. Type Property
- 인스턴스 프로퍼티는 특정 인스턴스에 속한 프로퍼티를 말합니다. 이 프로퍼티는 새로운 인스턴스가 생성될 때마다 새로운 프로퍼티도 같이 생성됩니다. 타입 프로퍼티는 특정 타입에 속한 프로퍼티로 그 타입에 해당하는 단 하나의 프로퍼티만 생성됩니다.
10. Type Property Syntax
- 타입 프로퍼티를 선언을 위해서는 static 키워드를 사용합니다. 클래스에서는 static과 class 이렇게 2가지 형태로 타입 프로퍼티를 선언할 수 있는데 두 가지 경우의 차이는 서브클래스에서 overriding가능 여부입니다. class로 선언된 프로퍼티는 서브클래스에서 오버 라이딩이 가능합니다. 아래는 예시입니다.
<swift />
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
}
}
11. Querying and Setting Type Properties
- 인스턴스 프로퍼티와 마찬가지로 타입 프로퍼티도 점 연산자(dot operator)로 프로퍼티의 값을 가져오고 할당할 수 있습니다. 예시는 아래와 같습니다.
<swift />
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"

<swift />
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
}
}
}
}
var leftChannel = AudioChannel()
var rightChannel = AudioChannel()
leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// Prints "7"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "7"
rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// Prints "10"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "10"
내용은 https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html를 보면서 작성하였고 원문으로 작성된 내용을 옮기다 보니 이상한 부분이 있을 수 있습니다. 자세한 내용은 위의 링크를 확인해주시기 바랍니다.
'컴퓨터 언어 > Swift' 카테고리의 다른 글
(Swift) 11. Subscripts (서브스크립트) (0) | 2021.12.13 |
---|---|
(Swift) 10. Methods (메소드) (0) | 2021.12.11 |
(Swift) 8. Classes and Structures (클래스와 구조체) (0) | 2021.12.09 |
(Swift) 7. Enumerations (열거형) (0) | 2021.12.09 |
(Swift) 6. Closures (클로저) (0) | 2021.12.09 |