소소한개발팁
article thumbnail
반응형

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 키워드를 사용합니다. 클래스에서는 staticclass 이렇게 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를 보면서 작성하였고 원문으로 작성된 내용을 옮기다 보니 이상한 부분이 있을 수 있습니다. 자세한 내용은 위의 링크를 확인해주시기 바랍니다.

반응형
profile

소소한개발팁

@개발자 뱅

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!