[Swift๐Ÿฆฉ] #10 ํ”„๋กœํผํ‹ฐ

24012 ๋‹จ์–ด swiftiOSiOS
  • struct, class, enum ์•ˆ์— ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ณ , ๋Œ€์ฒด๋กœ ํŠน์ • ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค์ด๋‹ค.
  • ๊ทธ ์ค‘ ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋Š” struct, class ์•ˆ์—๋งŒ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ”„๋กœํผํ‹ฐ ๊ด€์ฐฐ์ž๋ฅผ ํ†ตํ•ด ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ , ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

1. Stored Property โญ๏ธ

์ €์žฅ๋œ ์ƒ์ˆ˜, ๋ณ€์ˆ˜.

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // 0, 1, 2
rangeOfThreeItems.firstValue = 6 // 6, 7, 8

let rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // 0, 1, 2
rangeOfThreeItems.firstValue = 6 // let ์œผ๋กœ ์„ ์–ธํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ๊ฐ€๋Šฅ.
// ํ•˜์ง€๋งŒ class ๋ผ๋ฉด? ๊ฐ€๋Šฅ. 
// rangeOfThreeItems = FixedLengthRange(firstRange: 1, elength: 4) ์ฒ˜๋Ÿผ 
// ์•„์˜ˆ ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅ.

lazy

์‚ฌ์šฉ๋˜๊ธฐ ์ „๊นŒ์ง€ ์ดˆ๊ธฐ๊ฐ’์ด ๊ณ„์‚ฐ๋˜์ง€ ์•Š๋Š” ํ”„๋กœํผํ‹ฐ.
์ดˆ๊ธฐํ™” ์™„๋ฃŒ ํ›„์—๋„ ์ดˆ๊ธฐ๊ฐ’์ด ์—†์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— var ๋กœ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค. let ์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์ดˆ๊ธฐํ™” ์ „์— ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•ด์„œ lazy ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ.

lazy var tableView: UITableView = {
    let v = UITableView()
    v.register(UITableViewCell.self, reuseIdentifier: "cell")
    v.delegate = self
    v.dataSource = self
    return v
}()

2. Computed Property โญ๏ธโญ๏ธ

๊ฐ’์„ ์‹ค์งˆ์ ์œผ๋กœ ์ €์žฅํ•˜์ง€ ์•Š๊ณ , ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ๊ฐ„์ ‘์ ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ์„ค์ •. getter, setter

let start = 0
var end = 10
var mid {
    get { return (start + end) / 2 }
    // set(newMid) { end = 2 * newMid }
    set { end = 2 * newValue } // ์ž๋™ ์ œ๊ณต.
}
var readOnlyMid {
    return (start + end) / 2
}

3. Property Observer โญ๏ธโญ๏ธ

ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ๊ด€์ฐฐํ•˜๊ณ  ์‘๋‹ตํ•œ๋‹ค.
์ƒˆ๋กœ์šด ๊ฐ’๊ณผ ํ˜„์žฌ ๊ฐ’์ด ๊ฐ™์•„๋„ ํ”„๋กœํผํ‹ฐ์— ๊ฐ’์ด ์„ค์ •๋  ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.

  • ์ •์˜ํ•œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ
  • ์ƒ์†๋œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ
  • ์ƒ์†๋œ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ

์—์„œ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. (์ „์—ญ ๋ณ€์ˆ˜์™€ ์ •์˜ํ•œ ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ)


  • willSet : ๊ฐ’ ์ €์žฅ ์ง์ „์— ํ˜ธ์ถœ. (newValue๋กœ ์ €์žฅ๋  ๊ฐ’ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
  • didSet : ์ƒˆ๋กœ์šด ๊ฐ’์ด ์ €์žฅ๋˜์ž๋งˆ์ž ํ˜ธ์ถœ. (oldValue ๋กœ ๋ฐฉ๊ธˆ ์ €์žฅ๋œ ๊ฐ’ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)

์ฃผ์˜ : ์—ฌ๊ธฐ์„œ ์ž๊ธฐ ์ž์‹ ์„ ๋‹ค์‹œ set ํ•ด๋ฒ„๋ฆฌ๋ฉด?? ๋ฌดํ•œ ๋ฃจํ”„๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ.

class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

+) inout ํ•จ์ˆ˜์— willSet, didSet ์ด ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ธ์ž๋กœ ๋„˜๊ฒผ์„ ๋•Œ, ํ•ญ์ƒ ๊ฐ’์ด ์ƒˆ๋กœ ๋ฎ์–ด์“ฐ๊ธฐ๋˜๋ฏ€๋กœ ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ๋๋‚˜๋Š” ์‹œ์ ์— willSet didSet ์ด ๋ชจ๋‘ ํ˜ธ์ถœ๋œ๋‹ค.


4. Property Wrapper โ“

๊ฐ’์ด ์‹ค์ œ๋กœ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ํ”„๋กœํผํ‹ฐ, ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋‹ค. ๋กœ์ง์ด ์ž์ฃผ ์“ฐ์ด๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์ด ์žˆ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ๊ด€๋ฆฌํ•ด์ฃผ์ž.

  • ๊ตฌ์กฐ์ฒด์— @propertyWrapper ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์„œ ์ •์˜ํ•˜๊ณ ,
  • ์‚ฌ์šฉํ•  ๊ณณ์—์„œ @๊ตฌ์กฐ์ฒด์ด๋ฆ„ ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉํ•œ๋‹ค.
@propertyWrapper
struct TwelveOrLess {
    private var number = 0
    // number ์— ์ง์ ‘ ์ ‘๊ทผ X, wrappedValue ๋ฅผ ํ†ตํ•œ ์ ‘๊ทผ๋งŒ ๊ฐ€๋Šฅ.
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

struct SmallRectangle {
    // ๊ฐ€๋กœ ์„ธ๋กœ๊ฐ€ ๋ชจ๋‘ 12 ์ดํ•˜์ธ์ง€ ํ™•์ธ.
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

// ๊ฐ™์€ ์—ญํ• ์„ ํ•˜๋Š” ์ฝ”๋“œ์ด์ง€๋งŒ wrapping ์„ ์ด๋ ‡๊ฒŒ ํ• ์ˆ˜๋„ ์žˆ์Œ.
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 }
    }
}

init for property wrapping

property wrapping ์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ์—์„œ ์ดˆ๊ธฐ์ž๋ฅผ ์ •์˜ํ•˜๊ณ , ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

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

struct ZeroRectangle {
    @SmallNumber var height: Int // init ์‚ฌ์šฉ
    @SmallNumber var width: Int = 1 // init(wrappedValue: ) ์‚ฌ์šฉ
    
    // init(wrappedValue:  maximum: ) ์‚ฌ์šฉ
    @SmallNumber(wrappedValue: 3, maximum: 10) var height2: Int 
    @SmallNumber(maximum: 9) var width2: Int = 2 
}

var zeroRectangle = ZeroRectangle()
print(zeroRectangle.height, zeroRectangle.width)
// Prints "0 0"

๊ฐ’ ํˆฌ์˜

์ €์žฅํ•  ๊ฐ’์˜ ๋ณ€ํ™”๋ฅผ ํ•„์š”ํ•œ ๊ฐ’์œผ๋กœ ํˆฌ์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@propertyWrapper
struct SmallNumber {
    private var number: Int
    private(set) var projectedValue: Bool 
    // number ๊ฐ€ ํฐ ๊ฐ’์ธ์ง€์— ๋Œ€ํ•œ Bool ๊ฐ’์œผ๋กœ number ๋ฅผ ํˆฌ์˜.

    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"

-> ๊ทผ๋ฐ ๊ฒฐ๊ตญ wrappedValue ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ผ ํ…๋ฐ projectedValue ์—๋Š” ์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•˜๋Š”๊ฑฐ์ง€..?? ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ, wrappedValue, projectedValue ๋ผ๋Š” ํ‚ค์›Œ๋“œ ์ž์ฒด๊ฐ€ ํ”„๋กœํผํ‹ฐ ๋ž˜ํ•‘์—์„œ ์ œ๊ณต๋˜๋Š” ๊ฒƒ.

-> presenter ์—์„œ ์™ธ๋ถ€์—์„œ๋Š” subject ๋ฅผ asObservable, asObserver ๋‹ค๋ฃจ๊ฒŒ ํ•˜๋Š”๋ฐ, ๋งŽ์ด ๊ฒน์น˜๋ฏ€๋กœ ์ด ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„๋“ฏ.


5. ์ „์—ญ, ์ง€์—ญ

  • ์ „์—ญ : ํ•จ์ˆ˜, ๋ฉ”์„œ๋“œ, ํด๋กœ์ €, ๋˜๋Š” ํƒ€์ž… ์ปจํ…์ŠคํŠธ ์™ธ๋ถ€์— ์ •์˜๋œ ๋ณ€์ˆ˜
  • ์ง€์—ญ : ํ•จ์ˆ˜, ๋ฉ”์„œ๋“œ, ํด๋กœ์ €, ๋˜๋Š” ํƒ€์ž… ์ปจํ…์ŠคํŠธ ๋‚ด๋ถ€์— ์ •์˜๋œ ๋ณ€์ˆ˜

์ „์—ญ ์ƒ์ˆ˜, ๋ณ€์ˆ˜๋Š” ํ•ญ์ƒ lazy ๋กœ ๊ณ„์‚ฐ๋œ๋‹ค.


6. Type Property โญ๏ธ

์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ์ƒ์„ฑ๋˜๋Š” ํ”„๋กœํผํ‹ฐ์™€ ๋‹ค๋ฅด๊ฒŒ, ํƒ€์ž… ํ•˜๋‚˜์— ์ƒ์„ฑ๋˜๋Š” ํ”„๋กœํผํ‹ฐ.
๊ธฐ๋ณธ๊ฐ’์„ ํ•ญ์ƒ ์ค˜์•ผํ•˜๊ณ , ๊ธฐ๋ณธ์ ์œผ๋กœ lazy ๋กœ ๋™์ž‘ํ•œ๋‹ค.
์ €์žฅ / ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ๋กœ ๋ชจ๋‘ ์ •์˜ ๊ฐ€๋Šฅ
์ •์˜ํ•˜๋Š” ๋ฌธ์žฅ ์•ž์— static ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉํ•œ๋‹ค.

struct UserInfo {
    static var uuid: String {
        return UUID().uuidString
    }
    static var name: String = "์ดˆ๊ธฐ๊ฐ’"
}

print(UserInfo.uuid)

+) struct ๋ณด๋‹ค๋Š” enum ์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๋ ค๊ณ . enum ์€ ์ดˆ๊ธฐ์ž๊ฐ€ ์—†์œผ๋‹ˆ๊นŒ!!



์งˆ๋ฌธ

property wrapper์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•˜์‹œ์˜ค.

  • property ์„ ์–ธ, ์‚ฌ์šฉ์„ ๋”ฐ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ๋ฒ•์ด๋‹ค.
  • private ์œผ๋กœ ์‹ค์ œ ๊ฐ’์„ ์ €์žฅํ•  ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ณ ,
  • wrappedValue ์— getter, setter ๋ฅผ ์ด์šฉํ•ด์„œ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ณ  ์„ค์ •ํ•œ๋‹ค.
  • projectedValue ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ณ€์ˆ˜์™€ ๊ด€๋ จ๋œ ๊ฐ’์„ ํˆฌ์˜ํ•ด์„œ ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ๋‹ค.
  • ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์— ์ ์šฉํ•ด๋ณด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.



์ฐธ๊ณ 
https://bbiguduk.gitbook.io/swift/language-guide-1/properties

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ