Skip to content

Latest commit

ย 

History

History
539 lines (438 loc) ยท 18.3 KB

Properties.md

File metadata and controls

539 lines (438 loc) ยท 18.3 KB

Properties

  • Computed Property๋Š” enum์—์„œ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • Stored Property๋Š” class์™€ structure์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค

  • ์ธ์Šคํ„ด์Šค์— ํ”„๋กœํผํ‹ฐ ์ด์™ธ์—๋„ ํƒ€์ž… ์ž์ฐจ์— ๋Œ€ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š”๋ฐ(static) ์ด๋ฅผ Type Property๋ผ๊ณ  ํ•œ๋‹ค.

Stored Properties

  • ํด๋ž˜์Šค๋‚˜ ์ŠคํŠธ๋Ÿญ์ฒ˜์˜ ์ธ์Šคํ„ด์Šค์— ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹
  • var, let ์‚ฌ์šฉ๊ฐ€๋Šฅ

Stored Properties of Constant Structure Instances

  • ์ŠคํŠธ๋Ÿญ์ฒ˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ let์œผ๋กœ ์ €์žฅํ•˜๋ฉด ์ŠคํŠธ๋Ÿญ์ฒ˜ ๋‚ด๋ถ€์˜ ๊ฐ’์„ ๋ฐ”๊ฟ€์ˆ˜ ์—†๋‹ค.(var๋กœ ์„ ์–ธํ•˜์˜€๋‹ค ํ•˜๋”๋ผ๋„)
  • ์•„๋ž˜ ์˜ˆ์‹œ
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue = 6
// this will report an error, even though firstValue is a variable property
  • ๊ทธ ์ด์œ ๋Š” ์ŠคํŠธ๋Ÿญ์ฒ˜์— value type์ด๊ธฐ ๋•Œ๋ฌธ์ž„. ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์ˆ˜ํ™”๋˜์–ด์„œ ๋‚ด๋ถ€์˜ ํ”„๋กœํผํ‹ฐ ๋งˆ์ € ์ƒ์ˆ˜ํ™”๋˜์–ด๋ฒ„๋ฆผ

  • ํ•˜์ง€๋งŒ ํด๋ž˜์Šค๋Š” reference type์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅด๋‹ค. ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์ˆ˜๋กœ ์„ ์–ธ๋˜์–ด๋„ ๋‚ด๋ถ€์˜ var๋กœ ์„ ์–ธ๋œ stored property๋“ค์€ ๋ณ€๊ฒฝ๊ฐ€๋Šฅํ•˜๋‹ค.

Lazy Stored Properties

  • lazy Stored property๋Š” ๊ฐ’์ด ์‚ฌ์šฉ๋˜๊ธฐ ์ „๊นŒ์ง€ ์ดˆ๊ธฐ๊ฐ’์ด ์—ฐ์‚ฐ๋˜์ง€ ์•Š๋Š”๋‹ค.

NOTE lazy property๋Š” ๋ณ€์ˆ˜๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.(์ƒ์ˆ˜ ๋ถˆ๊ฐ€๋Šฅ) ์ƒ์ˆ˜๋Š” ์ธ์Šคํ„ด์Šค์˜ ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚˜๊ธฐ ์ „์— ๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ lazy property๋Š” ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚˜๋„ ๊ฐ’์ด ์—†๊ธฐ๋•Œ๋ฌธ์— ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

  • lazy Stored property๋Š” 2๊ฐ€์ง€ ์šฉ๋„๋กœ ๋งŽ์ด ์“ฐ์ด๋Š”๋ฐ
    1. property์˜ ์ดˆ๊ธฐ๊ฐ’์ด ์™ธ๋ถ€์˜ ๊ฐ’์œผ๋กœ ๋ถ€ํ„ฐ ์ •ํ•ด์ง€๋Š” ๊ฒฝ์šฐ
    2. property์˜ ๊ฐ’์„ ๊ตฌํ•  ๋•Œ ์—ฐ์‚ฐ์ด ๋งŽ์ด ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ

์•„๋ž˜ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ DataImporter์—์„œ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„๋•Œ ๊ฝค๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค. DataManager๊ฐ€ ๋‹จ์ˆœํžˆ data array์— ๋ฐ์ดํ„ฐ๋งŒ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด importer๊ฐ€ ํ•„์š”์—†์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ lazy keyword๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด importer๊ฐ€ ์ง„์งœ ํ•„์š”ํ•œ ์‹œ์ ์— ์ƒ์„ฑ๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

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 hasn't yet been created

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์ „๊นŒ์ง€ importer๋Š” ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š๋Š”๋‹ค.

print(manager.importer.filename)
// the DataImporter instance for the importer property has now been created
// Prints "data.txt"

NOTE ๋งŒ์•ฝ lazy stored property๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ์— ์˜ํ•ด ๋™์‹œ์— ์ ‘๊ทผ๋œ๋‹ค๋ฉด, ๋”ฑํ•œ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™”๋œ๋‹ค๋Š” ๋ณด์žฅ์€ ์—†๋‹ค

Stored Properties and Instance Variables

If you have experience with Objective-C, you may know that it provides two ways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property.

Swift unifies these concepts into a single property declaration. A Swift property doesnโ€™t have a corresponding instance variable, and the backing store for a property isnโ€™t accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the propertyโ€™s declaration into a single, definitive statement. All information about the propertyโ€”including its name, type, and memory management characteristicsโ€”is defined in a single location as part of the typeโ€™s definition.

Computed Properties

  • Enumeration์—๋Š” Stored property๊ฐ€ ์—†์ง€๋งŒ Computed property๋Š” ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜๋Š” ์—†๋‹ค.
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์— ๊ตณ์ด newCenter๋ฅผ ๋ช…์‹œ ์•ˆํ•ด๋„ newValue๋กœ ์ ‘๊ทผํ•ด์„œ set ์‹œ๊ธฐ์— ๋ฐ›์„ ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์œ„์™€ ๊ฐ™์€ ๋™์ž‘์„ ํ•œ๋‹ค.
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๊ฐ€ ํ•œ์ค„๋กœ๋งŒ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค๋ฉด(single expression) ๊ตณ์ด return์„ ์•ˆ์ ์–ด๋„ return ๋œ๋‹ค.
    • ์œ„์˜ ๋ฃฐ์€ function์—์„œ๋„ ๊ทธ๋Œ€๋กœ ์ž‘๋™ํ•œ๋‹ค(Implicit Return)
  • ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์œ„์™€ ๊ฐ™์€ ๋™์ž‘์„ ํ•œ๋‹ค.
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

  • computed property์— getter๋งŒ ์žˆ๊ณ  setter๊ฐ€ ์—†๋‹ค๋ฉด ์ฝ๊ธฐ ์ „์šฉ computed property๋ผ๊ณ  ํ•œ๋‹ค.
    • ํ‘œํ˜„๋งŒ์œผ๋กœ ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ ์ฝ๊ธฐ๋งŒ ๋˜๊ณ  set์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.

NOTE Computed property๋Š”(read-only computed propertyํฌํ•จ) ํ•ญ์ƒ var๋กœ ์„ ์–ธ๋˜์–ด์•ผ ํ•œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ณ ์ •๋œ ๊ฐ’์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ƒ์ˆ˜๋Š” ์ธ์Šคํ„ด์Šค ์ดˆ๊ธฐํ™”ํ›„์— ํ• ๋‹น๋œ ๊ฐ’์ด ๋ณ€ํ•˜๋ฉด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

(You must declare computed propertiesโ€”including read-only computed propertiesโ€”as variable properties with the var keyword, because their value isnโ€™t fixed. The let keyword is only used for constant properties, to indicate that their values canโ€™t be changed once theyโ€™re set as part of instance initialization.)

  • read-only computed property๋Š” 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

  • ํ”„๋กœํผํ‹ฐ์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์‹œํ•˜๋Š” ๋ฌธ๋ฒ•
  • ํ”„๋กœํผํ‹ฐ์— property observer๋ฅผ ๋‹ฌ๋ฉด ํ”„๋กœํผํ‹ฐ์˜ ์ƒˆ๋กœ์šด ๊ฐ’์ด ํ• ๋‹น๋  ๋•Œ๋งˆ๋‹ค property observer๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
    • ํ˜„์žฌ ๊ฐ’๊ณผ ๊ฐ™์€ ๊ฐ’์„ ํ• ๋‹นํ•ด๋„ property observer๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ณณ์„ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

  • Stored properties that you define

  • Stored properties that you inherit

  • Computed properties that you inherit

  • ์ƒ์†๋œ ํ”„๋กœํผํ‹ฐ์— ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” property๋ฅผ overrideํ•ด์„œ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

  • ์œ„์˜ 3๊ณณ์ค‘์— ์–ธ๊ธ‰์ด ๋˜์ง€ ์•Š์€ ์ง์ ‘ ์ •์˜ํ•œ computed property์˜ ๊ฒฝ์šฐ setter๊ฐ€ property observer์˜ ์—ญํ• ์„ ๋Œ€์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๋Š” ์•„๋ž˜ ํ‘œ๊ธฐ๋œ๊ฒƒ์ฒ˜๋Ÿผ 2๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค:

  • willSet: ๊ฐ’์ด ์ €์žฅ๋˜๊ธฐ ์ง์ „์— ์‹คํ–‰๋œ๋‹ค.

  • didSet: ๊ฐ’์ด ์ €์žฅ๋˜์ž๋งˆ์ž ์‹คํ–‰๋œ๋‹ค.

  • willSet ์˜ต์ €๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์ƒˆ๋กœ ํ• ๋‹น๋œ ๊ฐ’์ด ์ƒ์ˆ˜ ์ธ์ž๋กœ ๋„˜์–ด์˜ค๊ฒŒ ๋œ๋‹ค. ์ด ์ธ์ž์˜ ์ด๋ฆ„์„ ์ƒˆ๋กœ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๊ณ  newValue๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • didSet๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์›๋ž˜ ์ง€์ •๋˜์—ˆ๋˜ ๊ฐ’์ด ์ƒ์ˆ˜ ์ธ์ž๋กœ ๋„˜์–ด์˜ค๊ฒŒ ๋œ๋‹ค. ์ธ์ž์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด oldValude๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

NOTE The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They arenโ€™t called while a class is setting its own properties, before the superclass initializer has been called.

For more information about initializer delegation, see Initializer Delegation for Value Types and Initializer Delegation for Class Types.

willSet, 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

NOTE ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๊ฐ€ ๋‹ฌ๋ฆฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•จ์ˆ˜์˜ in-out parameter๋กœ ๋„ฃ๋Š”๋‹ค๋ฉด willSet๊ณผ didSet์ด ํ•ญ์ƒ ํ˜ธ์ถœ๋œ๋‹ค. in-out parameter๋Š” copy-in, copy-out ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ๋•Œ๋ฌธ์ธ๋ฐ ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋ ๋•Œ ์ธ์ž๋กœ ๋„˜์–ด์˜จ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ•ญ์ƒ ๋ฎ์–ด์“ฐ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Property Wrappers

ํ”„๋กœํผํ‹ฐ๋งˆ๋‹ค ๋™์ผํ•œ ๋™์ž‘์„ ํ•ด์•ผํ•  ๋•Œ ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŽธํ•˜๋‹ค

ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ๋ฅผ ๋งŒ๋“œ๋ ค๋ฉด ๊ตฌ์กฐ์ฒด, enum, class์— wrappedValue ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค.

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

NOTE ์œ„์— ์ฝ”๋“œ์—์„œ number์— ๊ฒฝ์šฐ wrappedValue๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ private์œผ๋กœ ์„ ์–ธ๋˜์–ด ์žˆ๋Š”๊ฒƒ์„ ์ฃผ์˜!

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"

height ์™€ width ํ”„๋กœํผํ‹ฐ๋Š” ์œ„์˜ TwelveOrLess์—์„œ ์ •์˜๋œ ๋Œ€๋กœ ์ดˆ๊ธฐ๊ฐ’ 0์„ ๊ฐ–๋Š”๋‹ค. height์— 10์„ ๋„ฃ์œผ๋ฉด 10์ด ์ €์žฅ๋˜๊ณ  height์— 24๋ฅผ ํ• ๋‹นํ•˜๋ฉด min(newValue, 12)์— ์˜ํ•ด 12๊ฐ€ ํ• ๋‹น๋œ๋‹ค.

ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ๋Š” @์„ ํ†ตํ•ด ๋ฌธ๋ฒ•์  ๊ฐ„ํŽธํ•จ์„ ์ œ๊ณตํ•˜๋Š”๋ฐ ๋งŒ์•ฝ ์ด ๊ธฐํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

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

Setting Initial Values for Wrapped Properties

์œ„์—์„œ๋Š” ํ”„๋กœํผํ‹ฐ๋ž˜ํผ๋ฅผ ์ ์šฉํ•œ ํ”„๋กœํผํ‹ฐ์˜ ์ดˆ๊ธฐ๊ฐ’์€ 0์œผ๋กœ ๊ณ ์ •๋˜์—ˆ์—ˆ๋‹ค. ์—ฌ๊ธฐ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ดˆ๊ธฐ๊ฐ’์„ ์ฃผ๊ธฐ์œ„ํ•ด ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ์— ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

@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
    @SmallNumber var width: Int
}

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

๋‘๋ฒˆ์งธ ์ƒ์„ฑ์ž ์‚ฌ์šฉ ํ”„๋กœํผํ‹ฐ ๋ž˜ํผ๋ฅผ ์ ์šฉํ•œ ํ”„๋กœํผํ‹ฐ์— ์ดˆ๊นƒ๊ฐ’์„ ์ •ํ•ด์ฃผ๋ฉด ์ž๋™์œผ๋กœ init(wrappedValue: Int)๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์ง€์ •๋œ ์ดˆ๊ธฐ๊ฐ’์ด ์ธ์ž๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

struct UnitRectangle {
    @SmallNumber var height: Int = 1
    @SmallNumber var width: Int = 1
}

var unitRectangle = UnitRectangle()
print(unitRectangle.height, unitRectangle.width)
// Prints "1 1"

์„ธ๋ฒˆ์งธ ์ƒ์„ฑ์ž ์‚ฌ์šฉ ๋งŒ์•ฝ wrappedValue์ด์™ธ์˜ ์ธ์ž๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  ์‹ถ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

struct NarrowRectangle {
    @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int
    @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
}

var narrowRectangle = NarrowRectangle()
print(narrowRectangle.height, narrowRectangle.width)
// Prints "2 3"

narrowRectangle.height = 100
narrowRectangle.width = 100
print(narrowRectangle.height, narrowRectangle.width)
// Prints "5 4"

height์™€ width๋Š” ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์ด๋‹ค. ๊ฐ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋‹ค๋ฅธ ์ดˆ๊ธฐ ์„ค์ •์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ์ด 3๋ฒˆ์งธ ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๋„๋ฆฌ์“ฐ๋Š” ๋ฐฉ์‹์ด๋‹ค.

๋‹ค๋ฅธ ์ธ์ž๊ฐ€ ์žˆ๋”๋ผ๋„ wrappedValue๋Š” ์ดˆ๊ธฐ๊ฐ’์„ ์ง€์ •ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ž๋ฅผ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค. <- ์ด๊ฑฐ ํฌํ•œํ•˜๋„ค ์•„๋ž˜ height์™€ width๋ฅผ ๋ณด๋ฉด ๋œ๋‹ค.

struct MixedRectangle {
    @SmallNumber var height: Int = 1
    @SmallNumber(maximum: 9) var width: Int = 2
}

var mixedRectangle = MixedRectangle()
print(mixedRectangle.height)
// Prints "1"

mixedRectangle.height = 20
print(mixedRectangle.height)
// Prints "12"

Projecting a Value From a Property Wrapper

Property wrapper์— projected value๋ผ๋Š” ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค. $ํ‘œ์‹œ๋ฅผ ์ด์šฉํ•ด์„œ ์ถ”๊ฐ€์ ์ธ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ์ด๋ฆ„์€ projectedValue๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

@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"

projectedValue์€ ์–ด๋–ค ํƒ€์ž…๋„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ๋Š” boolํƒ€์ž…๋งŒ์„ ๋ฆฌํ„ดํ•˜๋Š”๋ฐ ๋” ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌํ„ดํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด costume type์„ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.

๋ฐ‘์— ์ฒ˜๋Ÿผ projectedNumber์— @height, @width๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ self๋Š” ์ƒ๋žต๊ฐ€๋Šฅํ•˜๋‹ค.

enum Size {
    case small, large
}

struct SizedRectangle {
    @SmallNumber var height: Int
    @SmallNumber var width: Int

    mutating func resize(to size: Size) -> Bool {
        switch size {
        case .small:
            height = 10
            width = 20
        case .large:
            height = 100
            width = 100
        }
        return $height || $width
    }
}

Global and Local Variables

stored property์™€ computed property๋ชจ๋‘ global, local scope์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ๋Š” ํƒ€์ž…์˜ property๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ช…์นญ์„ stoed variable, compputed variable์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

NOTE global ๋ณ€์ˆ˜๋‚˜ ์ƒ์ˆ˜๋Š” lazyํ‚ค์›Œ๋“œ๊ฐ€ ์—†์–ด๋„ ํ•ญ์ƒ lazyํ•˜๊ฒŒ ์ž‘๋™ํ•œใ„ทk. local ๋ณ€์ˆ˜์™€ ์ƒ์ˆ˜๋Š” lazyํ•˜๊ฒŒ ์ž‘๋™ํ•  ์ˆ˜ ์—†๋‹ค.(lazyํ‚ค์›Œ๋“œ ๋ถ™์ด๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค.)

์•„๋ž˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ local scope์—์„œ๋Š” property wrapper๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.(global scope์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ)

func someFunction() {
    @SmallNumber var myNumber: Int = 0

    myNumber = 10
    // now myNumber is 10

    myNumber = 24
    // now myNumber is 12
}

Type Properties

์ธ์Šคํ„ด์Šค์— ์ข…์†๋˜์ง€ ์•Š์€ type property๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ stored type property๋Š” lazyํ•˜๊ฒŒ ์ž‘๋™๋˜๋ฉด ๋™์‹œ์— ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผํ•œ๋‹ค ํ•˜๋”๋ผ๋„ ๋”ฑ ํ•œ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™” ๋˜๋Š”๊ฒŒ ๋ณด์žฅ๋œ๋‹ค. ๋˜ํ•œ stored type property๋Š” initializer๊ฐ€ ์—†๊ธฐ๋•Œ๋ฌธ์— ํ•ญ์ƒ ์ดˆ๊ธฐ๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

Type Property Syntax

type property๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ static ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹ค๋งŒ ํด๋ž˜์Šค์˜ computed ํ”„๋กœํผํ‹ฐ์˜ ๊ฒฝ์šฐ subclass๊ฐ€ override๋ฅผ ํ—ˆ์šฉํ•˜๋ ค๋ฉด classํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์•„๋ž˜๋Š” ์˜ˆ์‹œ class์— computed type property๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ class ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. (๊ทธ ์™ธ์—๋Š” ์ „๋ถ€ static ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.)

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

NOTE ์œ„์˜ ์˜ˆ์ œ๋Š” ๋ชจ๋‘ read-only์ธ๋ฐ read-write๋„ ๊ฐ™์€ ๋ฌธ๋ฒ•์œผ๋กœ ์ž‘์„ฑ๊ฐ€๋Šฅํ•จ.

Querying and Setting Type Properties

ํƒ€์ž… ํ”„๋กœํผํ‹ฐ์—๋„ ๊ฐ’์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ instance๊ฐ€ ์•„๋‹Œ type์— ์ €์žฅ๋˜๋Š”๊ฒƒ์„ ์ฃผ์˜ํ•ด์•ผ ํ•œใ„ทใ….

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"