프로퍼티

저장 프로퍼티(Stored Properties)

  • 가장 기본 형식으로 클래스 또는 구조체 인스턴스의 뿐으로 저장된 상수 또는 변수
struct FixedLengthRange {
	//저장 프로퍼티
    var firstValue: Int 
    let length: Int
}

// 상수로 생성된 구조체 인스턴스는 프로퍼티가 변수여도 수정이 불가능
// 클래스 인스턴스는 상수로 생성돼도 수정 가능
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
rangeOfFourItems.firstValue = 6 //error

지연 저장 프로퍼티(Lazy Stored Properties)

  • 처음 사용될 때까지 초기값이 계산되지 않는 프로퍼티
  • 지연 저장된 프로퍼티는 선언 전에 lazy 수정자를 붙여 나타낸다.

    프로퍼티 상수는 초기화가 완료되기 전에 항상 값을 가지고 있어야 하므로 lazy로 선언할 수 없다

  • 인스턴스의 초기화가 완료될 때까지 값을 알 수 없는 외부 요인에 인해 초기값이 달라질 때 유용
  • 초기값으로 필요할 때까지 수행하면 안되는 복잡하거나 계산 비용이 많이 드는 경우에도 유용
class DataImporter {
    var filename = "data.txt"
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
}

let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
print(manager.importer.filename)
  • 파일로 부터 데이터를 가져올 필요 없이 데이터를 관리할 수 있으므로 DataManager 인스턴스가 ataImporter 인스턴스를 처음 사용하는 경우에 생성하는 것이 더 합리적

연산 프로퍼티(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))
//사각형 센터를 연산 프로퍼티를 통해 get                 
let initialSquareCenter = square.center // (5.0, 5.0)

//사각형 센터를 연산 프로퍼티를 통해 set
square.center = Point(x: 15.0, y: 15.0) // (10.0 , 10.0)
  • setter가 새로운 값을 설정하는데 이름을 정의하지 않았다면 newValue 라는 기본 이름이 사용 ex) 위코드에서 newCenter를 설정해주지 않았다면 newValue이름으로 자동적으로 설정
  • getter의 전체 바디가 단일 표현식이라면 getter는 암시적으로 표현식을 반환

읽기전용 연산 프로퍼티 (Read-Only Computed Properties)

  • 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)
fourByFiveByTwo.volume // 40

프로퍼티 관찰자(Property Observers)

  • 프로퍼티의 값이 변경되는지 관찰하고 응답
  • 프로퍼티의 현재 값이 새로운 값과 같더라도 프로퍼티의 값이 설정될 때 호출
  • 프로퍼티에 관찰자를 정의하는 방법은 2가지 선택사항을 가지며 둘다 정의할 수도 있다

    willSet 은 값이 저장되기 직전에 호출
    didSet 은 새로운 값이 저장되자마자 호출

willSet

  • willSet 구현의 일부로 이 파라미터에 특정 이름을 가질 수 있다
  • willSet 관찰자는 상수 파라미터로 새로운 프로퍼티 값이 전달
  • 파라미터 명과 구현 내에 소괄호를 작성하지 않으면 파라미터는 newValue 의 기본 파라미터 명으로 만들어 짐

didSet

  • 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)

  • 프로퍼티가 저장되는 방법을 관리하는 코드와 프로퍼티를 정의하는 코드 사이에 분리 계층을 추가

TwelveOrLess 구조체는 래핑하는 값이 항상 12와 같거나 더 작은 숫자가 됌. 더 큰 숫자를 저장하도록 하면 12가 저장

@propertyWrapper
struct TwelveOrLess {
    private var number = 0
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

속성으로 프로퍼티 전에 래퍼의 이름을 작성하여 프로퍼티에 래퍼를 적용.
다음은 항상 12 이하인지 확인하기 위해 TwelveOrLess 프로퍼티 래퍼를 사용하여 사각형을 저장하는 구조체

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"

@TwelveOrLess 를 작성하는 대신에 TwelveOrLess구조체에 명시적으로 프로퍼티를 래핑

struct SmallRectangle {
    private var _height = TwelveOrLess()
    private var _width = TwelveOrLess()
    var height: Int {
        get { return _height.wrappedValue }
        set { _height.wrappedValue = newValue }
    }
    var width: Int {
        get { return _width.wrappedValue }
        set { _width.wrappedValue = newValue }
    }
}

타입 프로퍼티(Type Properties)

  • 타입 자체에 속하는 프로퍼티
  • 모든 인스턴스에서 사용할 수 있는 프로퍼티 상수 or 모든 인스턴스에 전역인 값을 저장하는 프로퍼티 변수와 같은 특정 타입에 모든 인스턴스에 보편적인 값을 정의하는데 유용
  • 저장 타입 프로퍼티에는 기본값이 항상 존재해야함
  • 초기화 시 저장된 타입 프로퍼티에 값을 할당할 수 있는 초기화를 가지고 있지 않기 때문
  • static 키워드로 타입 프로퍼티를 정의
  • 클래스 타입의 연산 타입 프로퍼티의 경우 class 키워드를 대신 사용하여 하위 클래스에서 상위 클래스의 구현을 재정의 가능
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
    }
}

좋은 웹페이지 즐겨찾기