-
Swift 5.6 Properties기술/iOS 2022. 3. 20. 17:45
Properties
Stored Properties
가장 간단한 형식으로 저장된 프로퍼티는 특정 클래스 또는 구조체의 인스턴스 부분으로 저장된 상수 또는 변수입니다. 기본 값을 제공 가능합니다.
Stored Properties of Constant Structure Instances
구조체의 인스턴스를 생성하고 상수로 할당하면 프로퍼티 변수로 선언되어있어도 인스턴스의 프로퍼티를 수정할 수 없습니다.
이는 클래스의 동작과는 다릅니다.
Lazy Stored Properties
지연 저장된 프로퍼티는 처음 사용될때까지 초기 값은 계산되지 않는 프로퍼티 입니다. lazy 수정자를 붙여 나타냅니다.
NOTE 인스턴스 초기화가 완료된 후에도 초기 값이 없을 수 있으므로 지연 프로퍼티는 var 키웓를 사용하여 변수로 선언해야 합니다. 프로퍼티 상수는 초기화 완료되기 전에 항상 값을 가지고 있어야 하므로 lazy 로 선언할 수 없습니다.
지연 프로퍼티는 인스턴스의 초기화가 완료될 때까지 값을 알 수 없는 외부 요인에 인해 초기값이 달라질 때 유용합니다. 지연 프로퍼티는 프로퍼티의 초기값으로 필요할 때까지 수행하면 안되는 복잡하거나 계산 비용이 많이 드는 경우에도 유용합니다.
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 print(manager.importer.filename) // the DataImporter instance for the importer property has now been created // Prints "data.txt"
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 // initialSquareCenter is at (5.0, 5.0) 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)"
Shorthand Setter Declaration
계산된 프로퍼티의 setter 가 새로운 값을 설정하는데 이름을 정의하지 않았다면 newValue 라는 기본 이름이 사용됩니다.
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) } } }
Shorthand Getter Declaration
getter 가 단일 표현식이라면 getter 는 암시적으로 표현식을 반환합니다.
struct CompactRect { var origin = Point() var size = Size() var center: Point { get { Point(x: origin.x + (size.width / 2), y: origin.y + (size.height / 2)) } set { origin.x = newValue.x - (size.width / 2) origin.y = newValue.y - (size.height / 2) } } }
Read-Only Computed Properties
setter 가 없고 getter 만 있는 계산된 프로퍼티는 읽기전용 계산된 프로퍼티라고 합니다. 읽기 전용 계산된 프로퍼티는 항상 값을 반환하고 점 구문으로 접근할 수 있지만 다른 값을 설정할 수 없습니다.
get 키워드와 중괄호를 삭제하고 읽기 전용 계산된 프로퍼티를 간결하게 선언할 수 있습니다.
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"
Property Observers
프로퍼티 관찰자는 프로퍼티의 값이 변경되는지 관찰하고 응답합니다. 프로퍼티 관찰자는 프로퍼티의 현재 값이 새로운 값과 같더라도 프로퍼티의 값이 설정될 때 호출됩니다.
아래의 위치에 프로퍼티 관찰자를 추가할 수 있습니다.
- 정의한 저장된 프로퍼티
- 상속한 저장된 프로퍼티
- 상속한 계산된 프로퍼티
상속한 프로퍼티의 경우 하위 클래스의 프로퍼티를 재정의하여 프로퍼티 관찰자를 추가합니다. 정의한 계산된 프로퍼티의 경우 관찰자를 생성하는 대신 프로퍼티의 setter 를 이용하여 값 변경을 관찰할 수 있습니다.
프로퍼티에 관찰자를 정의하는 방법은 2가지 선택사항을 가지며 둘 다 정의할 수 있습니다.
- willSet 은 값이 저장되기 직전에 호출됩니다.
- didSet 은 새로운 값이 저장되자마자 호출됩니다.
willSet 관찰자를 구현한다면 상수 파라미터로 새로운 프로퍼티 값이 전달됩니다. willSet 구현의 일부로 이 파라미터에 특정 이름을 가질 수 있습니다. 파라미터 명과 구현 내에 소괄호를 작성하지 않으면 파라미터는 newValue 의 기본 파라미터 명으로 만들어 질 수 있습니다.
유사하게 didSet 관찰자를 구현한다면 예전 프로퍼티 값을 포함한 상수 파라미터가 전달됩니다. 파라미터 명을 사용하거나 oldValue 인 기본 파라미터 명을 사용할 수 있습니다. didSet 관찰자 내의 프로퍼티에 값을 할당한다면 새로운 값으로 방금 설정한 값을 대체합니다.
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
Property Wrappers
프로퍼티 래퍼는 프로퍼티가 저장되는 방법을 관리하는 코드와 프로퍼티를 정의하는 코드 사이에 분리 계층을 추가합니다. 예를 들어 기본 데이터베이스에 저장하는 프로퍼티가 있는 경우 모든 프로퍼티에 해당 코드를 작성해야하지만 프로퍼티 래퍼가 있으면 관리 코드를 한번 작성한 다음 여러 프로퍼티에 적용하여 해당 관리 코드를 재사용합니다.
@propertyWrapper struct TwelveOrLess { private var number = 0 var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } } struct SmallRectangle { @TwelveOrLess var height: Int @TwelveOrLess var width: Int } var rectangle = SmallRectangle() print(rectangle.height) // Prints "0" rectangle.height = 10 print(rectangle.height) // Prints "10" rectangle.height = 24 print(rectangle.height) // Prints "12"
Setting Initial Values for Wrapped Properties
@propertyWrapper struct SmallNumber { private var maximum: Int private var number: Int var wrappedValue: Int { get { return number } set { number = min(newValue, maximum) } } init() { maximum = 12 number = 0 } init(wrappedValue: Int) { maximum = 12 number = min(wrappedValue, maximum) } init(wrappedValue: Int, maximum: Int) { self.maximum = maximum number = min(wrappedValue, maximum) } }
SmallNumber 의 정의는 init() , init(wrappedValue:) , init(wrappedValue:maximum:) 의 3개의 초기화를 포함합니다.
프로퍼티에 래퍼를 적용하지 않고 초기값을 지정하지 않으면 Swift 는 래퍼를 설정하기 위해 init 을 사용합니다.
struct ZeroRectangle { @SmallNumber var height: Int @SmallNumber var width: Int } var zeroRectangle = ZeroRectangle() print(zeroRectangle.height, zeroRectangle.width) // Prints "0 0"
Projecting a Value From a Property Wrapper
래핑된 값 외에도 프로퍼티 래퍼는 투영된 값 정의에 의해 추가적인 기능을 노출할 수 있습니다. 예를 들어 데이터베이스 접근을 관리하는 프로퍼티 래퍼는 투영된 값으로 flushDatabaseConnection 메서드를 노출할 수 있습니다. 투영된 값의 이름은 앞에달러 표시 ( $ ) 가 붙는 것을 제외하면 래핑된 값과 동일합니다.
@propertyWrapper struct SmallNumber { private var number: Int private(set) var projectedValue: Bool var wrappedValue: Int { get { return number } set { if newValue > 12 { number = 12 projectedValue = true } else { number = newValue projectedValue = false } } } init() { self.number = 0 self.projectedValue = false } } struct SomeStructure { @SmallNumber var someNumber: Int } var someStructure = SomeStructure() someStructure.someNumber = 4 print(someStructure.$someNumber) // Prints "false" someStructure.someNumber = 55 print(someStructure.$someNumber) // Prints "true"
프로퍼티 래퍼는 투영된 값으로 어떤 타입의 값도 반환할 수 있습니다. 이 예제에서 프로퍼티 래퍼는 숫자가 변경되었는지에 대한 정보만 노출합니다. 그래서 투영된 값으로 부울 값을 노출합니다. 더 많은 정보의 노출이 필요한 래퍼는 다른 데이터 타입의 인스턴스를 반환하거나 투영된 값으로 래퍼의 인스턴스를 노출하기 위해 self 를 반환할 수 있습니다.
Type Properties
인스턴스 프로퍼티는 특정 타입의 인스턴스에 속하는 프로퍼티입니다. 타입의 새로운 신스턴스를 만들때마다 다른 인스턴스와는 별도로 고유한 프로퍼티 값을 생성합니다.
인스턴스가 아닌 타입 자체에 속하는 프로퍼티를 정의할 수 있습니다.
Type property Syntax
static 키워드를 통해 타입 프로퍼티를 정의합니다. 클래스 타입의 경우 class 키워드를 사용하여 하위 클래스에서 상위 클래스의 구현을 재정의 할 수 있습니다.
Querying and Setting Type Properties
타입 프로퍼티는 인스턴스가 아닌 타입에 대해 조회되고 실행됩니다.
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"
'기술 > iOS' 카테고리의 다른 글
Swift 5.6 Subscripts (0) 2022.03.20 Swift 5.6 Methods (0) 2022.03.20 Swift 5.6 Structures and Classes (0) 2022.03.20 Swift 5.6 Enumerations (0) 2022.03.20 Swift 5.6 Closures (0) 2022.03.20 TAG