πŸ¦… Swift

Properties

KiwiπŸ’» 2022. 7. 4. 16:00

ν΄λž˜μŠ€λ‚˜ ꡬ쑰체, μ—΄κ±°μ²΄μ˜ 객체 μΈμŠ€ν„΄μŠ€κ°€ κ·Έ 내뢀에 가지고 μžˆλŠ” 객체의 μƒνƒœμ— κ΄€ν•œ 정보λ₯Ό λ§ν•œλ‹€.

  • μ €μž₯ ν”„λ‘œνΌν‹°: μΈμŠ€ν„΄μŠ€μ˜ μΌλΆ€λ‘œ μƒμˆ˜μ™€ λ³€μˆ˜ 값을 μ €μž₯
  • 계산 ν”„λ‘œνΌν‹°: 값을 μ €μž₯ν•˜λŠ” λŒ€μ‹ μ— 계산을 함( 클래슀, ꡬ쑰체, μ—΄κ±°ν˜•μ—μ„œ 제곡)
  • νƒ€μž… ν”„λ‘œνΌν‹°: ν”„λ‘œνΌν‹°λŠ” νƒ€μž… κ·Έ μžμ²΄μ™€ μ—°κ²°λ˜μ–΄ μžˆμ„ 수 μžˆλŠ”λ°, 이λ₯Ό νƒ€μž…ν”„λ‘œνΌν‹°λΌκ³  함

μ €μž₯ ν”„λ‘œνΌν‹° (Stored Properties)

μ €μž₯ ν”„λ‘œνΌν‹°λŠ” νŠΉμ • 클래슀 λ˜λŠ” ꡬ쑰체의 μΈμŠ€ν„΄μŠ€ μΌλΆ€λ‘œμ„œ μ €μž₯된 μƒμˆ˜ λ˜λŠ” λ³€μˆ˜μ΄λ‹€. λ˜ν•œ μ €μž₯ ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν• λ•Œ “κΈ°λ³Έκ°’ (Default Property Value)”λ₯Ό μ„€μ •ν•  수 μžˆλ‹€. 그리고 μ΄λŸ¬ν•œ μ €μž₯ ν”„λ‘œνΌν‹°λŠ” initializer(μƒμ„±μž)둜 μ΄ˆκΈ°ν™” μ‹œν‚¬ 수 도 μžˆλ‹€. μƒμ„±μžμ— μ˜ν•΄ μ΄ˆκΈ°ν™” 될 λ•ŒλŠ” ν•΄λ‹Ή ν”„λ‘œνΌν‹°κ°€ μƒμˆ˜λ‘œ μ„ μ–Έ λ˜μ—ˆλ‹€κ³  해도 μˆ˜μ •μ΄ κ°€λŠ₯ν•˜λ‹€.

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

μƒμˆ˜λ‘œ μ •μ˜λœ ꡬ쑰체 μΈμŠ€ν„΄μŠ€ (Stored Properties of Constant Structure Instances)

ꡬ쑰체의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³  μƒμˆ˜μ— ν• λ‹Ήν•˜λ©΄ ν”„λ‘œνΌν‹°κ°€ λ³€μˆ˜λ‘œ μ„ μ–Έλ˜μ–΄ μžˆμ–΄λ„ μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œνΌν‹°λ₯Ό μˆ˜μ •ν•  수 μ—†λ‹€.

let rangeOfFourItems = FixedLengthRange(firstValue : 0, length: 4)
// 이 λ²”μœ„λŠ” μ •μˆ˜ κ°’ 0, 1, 2, 3 을 λ‚˜νƒ€λƒ„

rangeOfFourItems.firstValue = 6. 
// μ΄λŠ” firstValue κ°€ λ³€μˆ˜ 속성일지라도, μ—λŸ¬λ₯Ό λ°˜ν™˜

μ΄λŸ¬ν•œ λ™μž‘μ€ ꡬ쑰체가 κ°’ νƒ€μž… 이기 λ•Œλ¬Έμ΄λ‹€. κ°’ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€κ°€ μƒμˆ˜λ‘œ μ„ μ–Έν•˜λ©΄ μΈμŠ€ν„΄μŠ€μ˜ λͺ¨λ“  ν”„λ‘œνΌν‹°μ— λŒ€ν•΄ μˆ˜μ •ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ, μ°Έμ‘°νƒ€μž…μΈ ν΄λž˜μŠ€μ—μ„œλŠ” 이것과 λ‹€λ₯Έ κ²°κ³Όκ°€ λ‚˜νƒ€λ‚œλ‹€. 클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμˆ˜λ‘œ 선언해도 μ„ μ–Έν•œ ν”„λ‘œνΌν‹°μ˜ 값은 λ³€κ²½ν•  수 μžˆλ‹€.

지연 μ €μž₯ ν”„λ‘œνΌν‹° (Lazy Stored Properties)

지연 μ €μž₯ ν”„λ‘œνΌν‹° (lazy stored property)λŠ” 처음 호좜될 λ•ŒκΉŒμ§€ μ΄ˆκΈ°κ°’μ€ κ³„μ‚°λ˜μ§€ μ•ŠλŠ” ν”„λ‘œνΌν‹° 이닀. 지연 μ €μž₯ ν”„λ‘œνΌν‹°λŠ” μ„ μ–Έ 전에 lazy ν‚€μ›Œλ“œλ₯Ό λΆ™μ—¬ λ‚˜νƒ€λ‚Έλ‹€.

NOTE❗️
μΈμŠ€ν„΄μŠ€ μ΄ˆκΈ°ν™”κ°€ μ™„λ£Œλœ 후에도 μ΄ˆκΈ°κ°’μ΄ 없을 수 μžˆμœΌλ―€λ‘œ 지연 ν”„λ‘œνΌν‹°λŠ” var ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ³€μˆ˜λ‘œ μ„ μ–Έν•΄μ•Ό ν•œλ‹€. ν”„λ‘œνΌν‹° μƒμˆ˜λŠ” μ΄ˆκΈ°ν™”κ°€ μ™„λ£Œλ˜κΈ° 전에 항상 값을 가지고 μžˆμ–΄μ•Ό ν•˜λ―€λ‘œ lazy둜 μ„ μ–Έν•  수 μ—†λ‹€.

ν•΄λ‹Ή 속성이 λ°˜λ“œμ‹œ μ²˜μŒλΆ€ν„° μ΄ˆκΈ°ν™”κ°€ ν•„μš”ν•˜μ§€ μ•Šμ€ 경우(일반적으둜 λ§Žμ€ λ©”λͺ¨λ¦¬ 곡간을 μ°¨μ§€ν•˜λŠ” 이미지 λ“±)에 μ΄ˆκΈ°ν™”λ₯Ό μ§€μ—°μ‹œν‚¬ 수 μžˆλ‹€.
(λΆˆν•„μš”ν•œ μ„±λŠ₯μ €ν•˜λ‚˜, λ©”λͺ¨λ¦¬ κ³΅κ°„μ˜ λ‚­λΉ„ 쀄일 수 있음)

계산 ν”„λ‘œνΌν‹° (Computed Properties)

클래슀, ꡬ쑰체, μ—΄κ±°ν˜•μ€ κ³„μ‚°λœ ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•  수 μžˆλ‹€. 이 μ—°μ‚°ν”„λ‘œνΌν‹°λŠ” μ‹€μ œ 값을 μ €μž₯ν•˜κ³  μžˆλŠ” 것이 μ•„λ‹ˆλΌ, getterκ³Ό optionalν•œ setterλ₯Ό μ œκ³΅ν•΄ 값을 νƒμƒ‰ν•˜κ³  κ°„μ ‘μ μœΌλ‘œ λ‹€λ₯Έ ν”„λ‘œνΌν‹° 값을 μ„€μ •ν•  수 μžˆλŠ” 방법을 μ œκ³΅ν•œλ‹€. 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)"

μœ„ μ½”λ“œλŠ” μ’Œν‘œμ™€ν¬κΈ°λ₯Ό κ°–λŠ” μ‚¬κ°ν˜•μ„ ν‘œν˜„ν•˜λŠ” ꡬ쑰체에 κ΄€ν•œ μ½”λ“œμ΄λ‹€. μ—¬κΈ°μ„œ Rect κ΅¬μ‘°μ²΄λŠ” μ‚¬κ°ν˜•μ˜ 쀑점을 ν‘œν˜„ν•˜λŠ” centerλΌλŠ” μ—°μ‚° ν”„λ‘œνΌν‹°λ₯Ό μ œκ³΅ν•œλ‹€. 이 ν”„λ‘œνΌν‹°λŠ” κ³„μ‚°λœ ν”„λ‘œνΌν‹°μ˜ μ •μ˜λŒ€λ‘œ 값을 직접 κ°–κ³  μžˆλŠ” 것이 μ•„λ‹ˆλΌ λ‹€λ₯Έ μ’Œν‘œμ™€ 크기 ν”„λ‘œνΌν‹°λ“€μ„ 적절히 μ—°μ‚°ν•΄μ„œ ꡬ할 수 μžˆλ‹€. (get) 또 set으둜 μ‚¬κ°ν˜•μ˜ 쀑점을 직접 μ„€μ •ν•  수 μžˆλŠ”λ°, 이 값을 μ„€μ •ν•  λ•Œ x, y μ’Œν‘œκ°€ μ–΄λ–€ 값을 κ°€μ Έμ•Όν•˜λŠ”μ§€ x, y에 μ μ ˆν•œ μ’Œν‘œκ°’μ„ λ„£μ–΄μ€€λ‹€.

square.center 을 톡해 square λ³€μˆ˜μ˜ center ν”„λ‘œνΌν‹°μ— μ ‘κ·Όν•˜λŠ”λ°, μ΄λŠ” center의 getter을 ν˜ΈμΆœν•˜μ—¬ ν˜„μž¬ 속성값을 κ°€μ Έμ˜¨λ‹€. κΈ°μ‘΄ 값을 λ°˜ν™˜ν•œλ‹€κΈ° λ³΄λ‹€λŠ”, μƒˆ Pointλ₯Ό κ³„μ‚°ν•˜μ—¬ λ°˜ν™˜ν•΄μ€€λ‹€. μœ„μ½”λ“œμ—μ„œ 보면, getterλŠ” (5,5)λΌλŠ” 쀑심점을 λ°˜ν™˜ν•œλ‹€.

κ·Έ λ‹€μŒ, center ν”„λ‘œνΌν‹°μ— (15, 15)λΌλŠ” μƒˆλ‘œμš΄ 값을 μ„€μ •ν–ˆλ‹€. μ΄λŠ” μ •μ‚¬κ°ν˜•μ„ 였λ₯Έμͺ½ μœ„, μ•„λž˜ κ·Έλ¦Όμ—μ„œλŠ” μ˜€λ Œμ§€μƒ‰ μ •μ‚¬κ°ν˜•μ˜ μœ„μΉ˜λ‘œ μ΄λ™μ‹œν‚¨λ‹€. center ν”„λ‘œνΌν‹°λ₯Ό μ„€μ •ν•˜λ©΄ center의 setter을 ν˜ΈμΆœν•˜λŠ”λ° μ΄λŠ” orginμ΄λΌλŠ” μ €μž₯ ν”„λ‘œνΌν‹°μ˜ x와 y값을 μˆ˜μ •ν•˜μ—¬ μ •μ‚¬κ°ν˜•μ„ μƒˆ μœ„μΉ˜λ‘œ μ΄λ™μ‹œν‚¨λ‹€.

square λΌλŠ” μƒˆλ‘œμš΄ Rect λ³€μˆ˜λ₯Ό μƒμ„±ν–ˆλ‹€. squareλ³€μˆ˜λŠ” (0,0) μ΄λΌλŠ” 원점과, (10, 10)μ΄λΌλŠ” 폭과 λ†’μ΄λ‘œ μ΄ˆκΈ°ν™”λœλ‹€. μ•„λž˜ 그림의 νŒŒλž€μƒ‰ μ‚¬κ°ν˜•μ΄ 이 μ‚¬κ°ν˜•μ΄λ‹€.

Shorted Setter Declaration (Setter μ„ μ–Έμ˜ κ°„λž΅ν•œ ν‘œν˜„)

μ•žμ˜ μ½”λ“œμ—μ„œλŠ” Setter의 인자 이름을 μ•„λž˜μ™€ 같이 set(newCenter)라고 λͺ…μ‹œν–ˆμ§€λ§Œ, λ§Œμ•½ μ΄λ ‡κ²Œ newCenter라고 인자 이름을 μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 인자 κΈ°λ³Έ 이름인 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)
        }
    }
}

μœ„ μ½”λ“œμ—μ„œλŠ” set λ©”μ†Œλ“œ μ•ˆμ—μ„œ 인자 이름을 μ§€μ •ν•˜μ§€ μ•Šμ•˜λŠ”λ°λ„ newValue.x, newValue.yλ₯Ό μ‚¬μš©ν•  수 μžˆλŠ” 것을 보싀 수 μžˆλ‹€.

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

getterμ—μ„œ return을 μƒλž΅ν–ˆλ‹€. μ΄λŠ” ν•¨μˆ˜μ—μ„œ return을 μƒλž΅ν•˜λŠ” 것과 λ™μΌν•œ κ·œμΉ™μ„ κ°–λŠ”λ‹€.

μ½κΈ°μ „μš© κ³„μ‚°λœ ν”„λ‘œνΌν‹° (Read-Only Computed Properties)

getter만 있고 setterλ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠλŠ” κ³„μ‚°λœ ν”„λ‘œνΌν‹°λ₯Ό μ½κΈ°μ „μš© κ³„μ‚°λœ ν”„λ‘œνΌν‹°λΌκ³  ν•œλ‹€. 즉, μ½κΈ°μ „μš© κ³„μ‚°λœ ν”„λ‘œνΌν‹°λŠ” λ°˜λ“œμ‹œ λ°˜ν™˜ 값을 μ œκ³΅ν•˜κ³  λ‹€λ₯Έ 값을 지정할 μˆ˜λŠ” μ—†λŠ” ν”„λ‘œνΌν‹°μ΄λ‹€.

NOTE❗️
μ½κΈ°μ „μš© κ³„μ‚°λœ ν”„λ‘œνΌν‹°λ₯Ό 포함해 κ³„μ‚°λœ ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έμ‹œμ—λŠ” λ°˜λ“œμ‹œ let이 μ•„λ‹ˆλΌ var둜 μ„ μ–Έν•΄μ•Όν•œλ‹€. 보톡 μ½κΈ°μ „μš©(read-only)이라 함은 ν•œλ²ˆ 값이 정해지면 λ³€ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— let으둜 μ„ μ–Έν•˜λŠ” 것이 λ§žμœΌλ‚˜ κ³„μ‚°λœ ν”„λ‘œνΌν‹°λŠ” μ½κΈ°μ „μš©(read-only)이라 ν•˜λ”λΌλ„ 계산 값에 따라 값이 λ³€ν•  수 있기 λ•Œλ¬Έμ— var둜 μ„ μ–Έν•œλ‹€.

ν”„λ‘œνΌν‹° κ΄€μ°°μž(Property Observers)

속성 κ΄€μ°°μžλŠ” 속성 값이 λ°”λ€ŒλŠ” κ±Έ κ΄€μ°°ν•˜μ—¬ μ‘λ‹΅ν•©λ‹ˆλ‹€. 속성 κ΄€μ°°μžλŠ” 속성 값을 μ„€μ •ν•  λ•Œλ§ˆλ‹€(μƒˆ 값이 ν˜„μž¬ 속성 κ°’κ³Ό 같아도) ν˜ΈμΆœλ©λ‹ˆλ‹€.

  • willSet : 값이 μ €μž₯되기 λ°”λ‘œ 직전에 호좜 됨
  • didSet : μƒˆ 값이 μ €μž₯되고 λ‚œ 직후에 호좜 됨

willSetμ—μ„œλŠ” μƒˆ κ°’μ˜ νŒŒλΌλ―Έν„°λͺ…을 지정할 수 μžˆλŠ”λ°, μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ κΈ°λ³Έ κ°’μœΌλ‘œ newValueλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
didSetμ—μ„œλŠ” λ°”λ€ŒκΈ° μ „μ˜ κ°’μ˜ νŒŒλΌλ―Έν„°λͺ…을 지정할 수 μžˆλŠ”λ°, μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ κΈ°λ³Έ κ°’μœΌλ‘œ oldValueλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

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