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

๋˜์ƒยท2022๋…„ 3์›” 25์ผ
0

iOS

๋ชฉ๋ก ๋ณด๊ธฐ
26/47
post-thumbnail
  • 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
}()

๐Ÿ“• ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š์€ lazy ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด, ์—ฌ๋Ÿฌ๋ฒˆ ์ดˆ๊ธฐํ™” ๋  ์ˆ˜๋„ ์žˆ๋‹ค.


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 ์€ ์ดˆ๊ธฐ์ž๊ฐ€ ์—†์œผ๋‹ˆ๊นŒ!!

๐Ÿ“• ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ’์— ์‚ฌ์šฉํ•œ๋‹ค.
๐Ÿ“• Stored, Computed ํ”„๋กœํผํ‹ฐ๋กœ ์ •์˜ ๊ฐ€๋Šฅ


7. ํ‚ค ๊ฒฝ๋กœ ๐Ÿ“•

  • ํ•จ์ˆ˜ ์ด๋ฆ„์„ ๋ณ€์ˆ˜์— ์ฐธ์กฐํ•ด์„œ ๋‚˜์ค‘์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ์ฒ˜๋Ÿผ,
  • ํ”„๋กœํผํ‹ฐ๋„ ๋ณต์‚ฌํ•ด์˜ค๊ฑฐ๋‚˜ ํ•˜์ง€ ์•Š๊ณ , ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์˜ ์œ„์น˜๋งŒ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • AnyKeyPath ํด๋ž˜์Šค์˜ WritableKeyPath<Root, Value> (๊ฐ’ ํƒ€์ž…), ReferenceWritableKeyPath<Root, Value>(์ฐธ์กฐ ํƒ€์ž…) ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ํƒ€์ž… ์™ธ๋ถ€๋กœ ๊ณต๊ฐœ๋œ ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๋‚˜ ์„œ๋ธŒ์Šคํฌ๋ฆฝํŠธ์— ํ•œํ•ด์„œ๋งŒ ํ‘œํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค.
class Person {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

struct Stuff {
    var name: String
    var owner: Person
}

print(type(of: \Person.name)) // ReferenceWritableKeyPath<Person, String>
print(type(of: \Stuff.name)) // WritableKeyPath<Person, String>


// KeyPath ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ.
let ddosang = Person(name: "ddosang")
let xiyeon = Person(name: "xiyeon")
let macbookAir = Stuff(name: "macbook Air", owner: ddosang)

let stuffNameKeyPath = \Stuff.name
let ownerKeyPath = \Stuff.owner
// ๊ฒฝ๋กœ๋ฅผ ๋ง๋ถ™์ผ ์ˆ˜๋„ ์žˆ๋‹ค.
let ownerNameKeyPath = ownerKeyPath.appending(path: \.name)

print(macbookAir[keyPath: stuffNameKeyPath]) // macbook Air
macbookAir[keyPath: ownerKeyPath] = xiyeon
print(macbookAir[keyPath: ownerNameKeyPath]) // xiyeon



์งˆ๋ฌธ

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

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



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

์•ผ๊ณฐ์˜ Swift5 Programming

profile
0๋…„์ฐจ iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€