Swift Properties
Properties - Stored Properties, Computed Properties, Property Observers, Property Wrappers, Type Properties
1. Stored Properties π©βπ»
Class, Structure, Enumerationμ instance μΌλΆλ‘μ¨ constant values
λλ variable values
λ₯Ό
μ μ₯νλ€.
1. Stored Properties
FixedLengthRange instance λ 1κ°μ variable firstValue μ 1κ°μ constant length λ₯Ό κ°μ§κ³ μλ€.
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
print(rangeOfThreeItems) // FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6
print(rangeOfThreeItems) // FixedLengthRange(firstValue: 6, length: 3)
firstValue λ var
λ‘ μ μΈνκΈ° λλ¬Έμ μμ κ°λ₯νλ€.
rangeOfThreeItems.length = 4 // Cannot assign to property: 'length' is a 'let' constant
length λ let
μΌλ‘ μ μΈνκΈ° λλ¬Έμ μμ μ΄ λΆκ°λ₯ν΄ μλ¬κ° λ°μλλ€.
2. Stored Properties of Constant Structure Instances
λ§μ½ Structure μ instance λ₯Ό μμ±ν΄ let
ν€μλμ ν λΉνλ©΄, instance μμ²΄κ° constant κ° λλ―λ‘
propertiesκ° variable μ΄λλΌλ μμ μ΄ λΆκ°λ₯νλ€.
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
rangeOfFourItems.firstValue = 3 // Cannot assign to property: 'rangeOfFourItems' is a 'let' constant
κ·Έλ¬λ μ΄κ²μ Structures
κ° Value Types
μ¬μ λ°μνλ νμμΌλ‘, Reference Types
μΈ Classes
λ
instance λ₯Ό let
ν€μλλ₯Ό μ΄μ©ν΄ constant λ‘ μ μΈν΄λ, properties κ° variable μ΄λ©΄ μ¬μ ν μμ κ°λ₯νλ€.
class FixedVolumeRange {
var firstValue: Int
let volume: Int
init(firstValue: Int, volume: Int) {
self.firstValue = firstValue
self.volume = volume
}
}
let rangeOfFiveVolumes = FixedVolumeRange(firstValue: 0, volume: 5)
print("rangeOfFiveVolumes(firstValue: \(rangeOfFiveVolumes.firstValue), volume: \(rangeOfFiveVolumes.volume))")
rangeOfFiveVolumes.firstValue = 1
print("rangeOfFiveVolumes(firstValue: \(rangeOfFiveVolumes.firstValue), volume: \(rangeOfFiveVolumes.volume))")
rangeOfFiveVolumes(firstValue: 0, volume: 5)
rangeOfFiveVolumes(firstValue: 1, volume: 5)
3. Lazy Stored Properties
1 ) Syntax
Lazy Stored Properties
λ μ¬μ©λκΈ° μ κΉμ§ μ΄κΈ°κ°μ΄ κ³μ°λμ§ μλ Stored Property λ€. Property μ μΈ
μμ lazy
modifier λΆμ¬ λ§λ€λ©°, λ°λμ var
ν€μλμ ν¨κ» μ¬μ©ν΄μΌνλ€. constant λ initialization
μ΄ μ’
λ£λκΈ° μ μ λ°λμ κ°μ κ°μ ΈμΌ νκΈ° λλ¬Έμ΄λ€(= μ μΈκ³Ό λμμ κ°μ μ μ₯ν΄μΌνλ€).
Lazy Stored Properties λ λ€μ κ²½μ° μ μ©νλ€
- μ΄κΈ°κ°μ΄ μΈλΆ μμΈμ μμ‘΄νλ κ²½μ°
- νμν λκΉμ§ μννλ©΄ μ λλ κ²½μ°
- μ΄κΈ°κ°μ μ μ₯νλλ° λΉμ©μ΄ λ§μ΄ λλ κ²½μ°
- μ΄κΈ°κ°μ΄ νμνμ§ μμ κ²½μ°
Syntax
struct SomeStructure {
lazy var someProperty = {
return // property definition goes here
}()
lazy var anotherProperty = SomeClass() // or SomeStructure()
}
2 ) Lazy Stored Property Examples
- μ΄κΈ°κ°μ΄ μΈλΆ μμΈμ μμ‘΄νλ κ²½μ°
class Classroom {
let subject: Subject
let maxStudents: Int
var applicant: Int = 0
lazy var students: Int = {
applicant > maxStudents ? maxStudents : applicant
}()
enum Subject {
case Korean, English, Math, History, Science
}
init(subject: Subject, maxStudents: Int) {
self.subject = subject
self.maxStudents = maxStudents
}
}
struct Classroom {
let subject: Subject
let maxStudents: Int
var applicant: Int = 0
lazy var students: Int = {
applicant > maxStudents ? maxStudents : applicant
}()
enum Subject {
case Korean, English, Math, History, Science
}
}
μμ κ°μ΄ lazy
λ Class μ Structure λͺ¨λμμ μ¬μ© κ°λ₯νλ€.
λ€μ μμ λ Structure λ₯Ό μ¬μ©νλ€.
var mathClass = Classroom(subject: .Math, maxStudents: 30)
var englishClass = Classroom(subject: .English, maxStudents: 50)
μν κ°μμ μμ΄ κ°μλ₯Ό κ°μ€νλ€. κ·Έλ¦¬κ³ μν κ°μλ μ΅λ μκ° μ μ² μΈμμ 30λͺ
, μμ΄ κ°μλ 50λͺ
μΌλ‘ μ ννλ€.
μ€μ κ°μλ₯Ό λ£λ νμ μλ₯Ό 미리 μ μ μμ΄ μκ° μΈμμ lazy
λ‘ κ³μ°μ 보λ₯νλλ‘ νλ€.
κ·Έλ¦¬κ³ κ°μλ₯Ό μ€νν ν 43λͺ μ΄ μν κ°μλ₯Ό μ μ²νλ€. κ°μ μκ° μ μ² κΈ°κ°μ΄ μ’ λ£λμλ€. μ΄μ μν κ°μλ₯Ό μΆλ ₯ν΄λ³΄μ.
Array(1...43).forEach { i in mathClass.applicant += 1 }
print(mathClass)
Classroom(subject: __lldb_expr_48.Classroom.Subject.Math,
maxStudents: 30,
applicant: 43,
$__lazy_storage_$_students: nil)
lazy
λ‘ μΈν΄ μμ§ κ°μλ₯Ό λ£λ νμ μλ μ ν΄μ§μ§ μμ nil
μΈ κ²μ νμΈν μ μλ€.
μ΄λ²μλ Lazy Stored Property λ₯Ό μ¬μ©ν΄ μ΄κΈ°κ°μ΄ μ μ₯λλλ‘ ν΄λ³΄μ.
mathClass.students
print(mathClass)
Classroom(subject: __lldb_expr_48.Classroom.Subject.Math,
maxStudents: 30,
applicant: 43,
$__lazy_storage_$_students: Optional(30))
Classroom Structure μ students property λ μ΄κΈ°κ°μ΄ μμΌλ―λ‘
nil
μ νμ©ν΄μΌ νκΈ° λλ¬ΈμInt
λ‘ μ μΈνμμλ λΆκ΅¬νκ³ instance μ체λ₯Ό μΆλ ₯νλ©΄Int?
μ¦,Optional
μΈ κ²μ νμΈν μ μλ€.
λν μ΄λμ property λ students κ° μλ$__lazy_storage_$_students
μΈ κ²λ νμΈν μ μλ€.
print("\(mathClass.students) students in math class") // 30 students in math class
νμ§λ§ ν΄λΉ Property λ₯Ό μ§μ μ κ·Όν΄λ³΄λ©΄ μ°λ¦¬κ° μ μν
Int
νμ μ κ°μ μ»μ΄μ€λ κ²μ λ³Ό μ μλ€. μ΄λ Lazy Stored Properties λ₯Ό μ¬μ©νλ μκ° Closure κ° μ€νλλ©° κ°μ μ μ₯νκΈ° λλ¬Έμ΄λ€. μ¦,lazy
λ‘ μΈν΄ κ°μ ν λΉ(μ μ₯)νλ κ²μ΄ μ§μ°μ΄ λλ€λ κ²μ μ μΈνλ©΄ Lazy Stored Properties λ μΌλ°μ μΈ Stored Properties μ κ°λ€λ κ²μ μ μ μλ€.
μ΄λ²μλ μμ΄ κ°μλ₯Ό μ€ννκ³ , 45λͺ μ΄ μμ΄ κ°μλ₯Ό μ μ²νλ€.
Array(1...10).forEach { i in englishClass.applicant += 1 }
print("\(englishClass.students) students in english class") // 10 students in english class
Array(1...35).forEach { i in englishClass.applicant += 1 }
print("\(englishClass.students) students in english class") // 10 students in english class
print(englishClass) // Classroom(subject: __lldb_expr_74.Classroom.Subject.English, maxStudents: 50, applicant: 45, $__lazy_storage_$_students: Optional(10))
κ·Έλ°λ° 10λͺ
μ΄ μ μ²ν μμ μ νμ μλ₯Ό ν λ² μ‘°ννλ€. μ΄ 45λͺ
μ΄ μ§μμ νμ§λ§ μ¬μ ν νμ μλ 10λͺ
μΌλ‘ μΆλ ₯λλ€!!
μκ° μ μ² κΈ°κ°μ΄ μ’
λ£λ ν μ‘°ννμ λ μ§μμ μλ 45λͺ
μΌλ‘ μ μμ μΌλ‘ μ μ₯ λμμΌλ νμμλ§ 10λͺ
μΈ μνμΈ κ²μ λ³Ό μ μλ€.
μ΄λ μ΄λ―Έ 10λͺ
μ΄ μ μ²ν μμ μ
ν΄λΉ Lazy Stored Property μ μ κ·Όν΄ μ΄κΈ°κ°μ΄ μ μ₯
λμκΈ° λλ¬Έμ΄λ€.
Lazy Stored Propertiesλ μ΅μ΄ μ¬μ©λλ μκ°μ κ°μ μ μ₯νλ€.
μ΄ν λ€μ μ¬μ©ν λλ μ΄λ―Έ μ§μ° μ μ₯λ κ°μ κ°μ Έμ€λ―λ‘ κ°μ΄ μ λ°μ΄νΈ λμ§ μλλ€.
λ§μ½, κ°μ λ§€λ² μ λ°μ΄νΈ νκΈ°λ₯Ό μνλ€λ©΄ μ μ₯νλ κ²μ΄ μλλΌ κ³μ°νλλ‘Computed Properties
λ₯Ό μ¬μ©ν΄μΌνλ€.
- μ΄κΈ°κ°μ μ μ₯νλλ° λΉμ©μ΄ λ§μ΄ λλ κ²½μ°
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
}
DataImporter
ν΄λμ€λ μΈλΆ νμΌλ‘λΆν° λ°μ΄ν°λ₯Ό κ°μ Έμ¨λ€.DataManager
ν΄λμ€λ data λΌλ μ΄λ¦μ Stored Property λ₯Ό λ€λ£¨λ ν΄λμ€λ‘[String]
μΌλ‘ μ μ₯λ λ°μ΄ν°λ₯Ό λ€λ£¬λ€. κ·Έλ¦¬κ³ μ΄ ν΄λμ€λ νμΌλ‘λΆν° λ°μ΄ν°λ₯Ό κ°μ Έμ¬ μ μλλ‘DataImporter
ν΄λμ€λ₯Ό ν¬ν¨νκ³ μλ€.
νμ§λ§ μΈλΆ νμΌμμ λ°μ΄ν°λ₯Ό κ°μ Έμ€λ κ²μ νμ νμν κ²μ΄ μλλ€. κ·Έλ¦¬κ³ μ΄λ¬ν κΈ°λ₯μ μ΄κΈ°ννλ κ²μ λΉμ©μ΄ λ§μ΄ λλ μμ μ΄λ€. λ°λΌμ ν΄λΉ instance λ μ²μ μ¬μ©ν λ μμ±νλ κ²μ΄ ν©λ¦¬μ μ΄λ€. κ·Έλ¬λ―λ‘ DataManager λ μ΄κ²μ Lazy Stored Property λ‘ μ μΈνλ€.
let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
DataManager μ instance μ λ¬Έμμ΄ 2κ°λ₯Ό μ μ₯νλ€.
νμ§λ§ μμ§ μΈλΆ νμΌμ κ°μ Έμ¬ μΌμ΄ μμκΈ° λλ¬Έμ DataImporter
instance λ μμ±λμ§ μμλ€.
print(manager.importer.filename)
// Prints "data.txt"
DataManager ν΄λμ€μ importer property μ λν DataImportor
instance κ° μμ±λμλ€!!
Lazy Stored Properties
λ₯Ό λ©ν° μ€λ λμμ λμμ access ν λ μμ§ properties κ° μ΄κΈ°ν λμ§ μμλ€λ©΄, ν λ²λ§ μ΄κΈ°νλλ€λ 보μ₯μ΄ μλ€. μ¦,Thread-UnSafe
νλ―λ‘ μ΄λ₯Ό μ μ΄ν νμκ° μλ€.
4. Stored Properties and Instance Variables
Objective-C λ Class instance μ Properties λ‘ Values μ References λ₯Ό μ μ₯νλ λ κ°μ§
λ°©λ²μ μ 곡νλ€. λν Properties λ₯Ό Backing Store(λ°±μ
μ μ₯μ)
λ‘ μ¬μ©ν μ μμλ€.
νμ§λ§ Swift λ Backing Store
μ μ§μ μ μν μ μλλ‘ νκ³ , Properties
λ₯Ό μ μ₯νλ λ°©μμ ν΅ν©νλ€.
λ°λΌμ μ μΈνλ λ°©λ²μ λ°λ₯Έ νΌλμ νΌνκ³ λͺ
νν λ¬Έμ₯μΌλ‘ λ¨μνλμμΌλ©°, μ΄λ Properties
μ μ΄λ¦
, νμ
,
λ©λͺ¨λ¦¬ κ΄λ¦¬ νΉμ±
μ ν¬ν¨νλ λͺ¨λ μ 보λ₯Ό μ νμ ν κ³³μμ μ μνλ€.
2. Computed Properties π©βπ»
1. Computed Properties
1 ) Syntax
Class, Structure, Enumeration μ μΌλΆλ‘μ¨ κ°μ μ μ₯νλ λμ κ³μ°
νλ©°, getter
μ
optional setter
λ₯Ό μ 곡νλ€. Lazy Stored Properties μ λ§μ°¬κ°μ§λ‘ λ°λμ var
ν€μλμ ν¨κ» μ¬μ©ν΄μΌνλ©°,
Lazy Stored Properties μ λ€λ₯΄κ² λ°λμ λ°μ΄ν° νμ
μ λͺ
μ(explicit type)ν΄μΌνλ€.
λν, κ°μ ν λΉ(μ μ₯)νλ κ²μ΄ μλλ―λ‘, =
λ₯Ό μ¬μ©νμ§ μκ³ , explicit type λ€μ λ°λ‘ getter μ setter λ₯Ό
κ°λ Closure
λ₯Ό μμ±νλ€. λν setter μ parameter λ λ°λμ λͺ
μλ explicit type κ³Ό λμΌν SomeType
μ΄μ΄μΌνλ―λ‘, λ³λμ type
μ λͺ
μν μ μλ€.
Syntax
struct SomeStructure {
var someProperty: SomeType {
get {
return // property definition for getter goes here
}
set (parameterName) {
// property definition for setter goes here
}
}
}
λ¨!!
Computed Properties
λ μ λ μκΈ° μμ μ λμμΌλ‘ ν΄μλ μ λλ€.
κ°ν μ°Έμ‘°κ° μμ±λκΈ° λλ¬Έμ΄λ€.struct SomeStructure { var someProperty: SomeType { get { self.someProperty } set { self.someProperty = newValue } } }
2 ) Computed Property Examples
- Case 1
첫 λ²μ§Έ μμ¬λ‘ μ Lazy Stored Properties μμ μ§λ©΄νλ μμ΄ κ°μ νμ μλ₯Ό νμΈν λ κ²ͺμλ λ¬Έμ λ₯Ό ν΄κ²°ν΄λ³΄μ.
struct Classroom {
let subject: Subject
let maxStudents: Int
var applicant: Int = 0
var students: Int {
get {
applicant > maxStudents ? maxStudents : applicant
}
}
enum Subject {
case Korean, English, Math, History, Science
}
}
var englishClass = Classroom(subject: .English, maxStudents: 50)
μμ λμΌνκ² μμ΄ κ°μλ₯Ό μ€ννκ³ μκ° μ μ²μ΄ μ§νλλ λμ€ μ¬λ¬ μ°¨λ‘ νμ μλ₯Ό νμΈνλ€.
Array(1...10).forEach { i in englishClass.applicant += 1 }
print("\(englishClass.students) students in math class") // 10 students in math class
Array(1...35).forEach { i in englishClass.applicant += 1 }
print("\(englishClass.students) students in math class") // 45 students in math class
Array(1...10).forEach { i in englishClass.applicant += 1 }
print("\(englishClass.students) students in math class") // 50 students in math class
μ Lazy Stored Properties μμ κ²ͺμλ λ¬Έμ μ λ¬λ¦¬ λ§€λ² μ΅μ κ°μ μ»μ μ μλ€! μ΄κ²μ Computed Properties κ°
μ€μ λ‘ κ°μ μ μ₯νλ κ²μ΄ μλ κ³μ°
νκΈ° λλ¬Έμ΄λ€.
print(englishClass)
Classroom(subject: main.Classroom.Subject.English,
maxStudents: 50,
applicant: 55)
Lazy Stored Properties μ λ€λ₯΄κ² instance λ₯Ό μ‘°νν λ μ‘°νκ° λμ§ μλλ€. μ μ₯λλ κ°μ΄ μλκΈ° λλ¬Έμ΄λ€.
μ¦,Properties
μ§λ§ νλμMethods
μ κ°κΉλ€(κ·Έλ λ€κ³ μ΄κ²μ΄ Methods μΈ κ²μ μλλ€. μ¬μ ν Properties λ€).
- Case 2
μ΄λ²μλ 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)
}
}
}
- Point: Cartesian Coordinates System μμ μλ μ μ μμΉ λ₯Ό encapsulates(μΊ‘μν) νλ€.
- Size: μ¬κ°νμ λλΉ μ ν μ encapsulates(μΊ‘μν) νλ€.
- Rect: μ¬κ°νμ μ μνλ€. μ΄λ₯Ό μν΄
Point
μSize
μ instances λ₯Ό κ°κ° origin κ³Ό size λΌλ Stored Properties λ‘ κ°κ³ , μ μλ μ¬κ°νμ μ€μ¬μ μ ꡬνκΈ° μν getter μ, μ€μ¬μ μ΄ μ΄λλμμ λ μ μ€μ¬μ μ λ°λΌ κΈ°μ€μ origin μ μ¬μ μνλ setter λ₯Ό κ°λComputed Property
λ₯Ό center λΌλ μ΄λ¦μΌλ‘ κ°κ³ μλ€.
var square = Rect(origin: Point(),
size: Size(width: 10, height: 10))
print(square.center) // Point(x: 5.0, y: 5.0)
square instance λ₯Ό λ§λ€μκ³ , μμ±λ instance λ‘λΆν° getter λ₯Ό μ΄μ©ν΄ μ¬κ°νμ μ€μ¬μ μ ꡬνλ€.
μ΄λ²μλ setter λ₯Ό μ΄μ©ν΄ μ κΈ°μ€μ μ μ μ₯νκ³ , λ³κ²½λ κΈ°μ€μ κ³Ό κ·Έλμ μ€μ¬μ μ ꡬν΄λ³΄μ.
square.center = Point(x: 17.5, y: 17.5)
print("""
square.origin: \(square.origin)
square.center: \(square.center)
""")
square.origin: Point(x: 12.5, y: 12.5)
square.center: Point(x: 17.5, y: 17.5)
2. Shorthand Getter/Setter Declaration
- Shorthand Setter Declaration
Trailing Closures κ° Parameters λ₯Ό μλ΅νλ©΄ κΈ°λ³Έκ°μΌλ‘ $0, $1, $2, ...
λ₯Ό μ¬μ©νλ κ²μ²λΌ
Computed Properties μ setter μ Parameters λ₯Ό μλ΅νλ©΄ κΈ°λ³Έκ°μΌλ‘ newValue
μ oldValue
λ₯Ό μ¬μ©νλ€.
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 {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
- Shorthand Getter Declaration
λ€λ₯Έ Closures μ λ§μ°¬κ°μ§λ‘ single expression μΌλ‘ μμ±λλ©΄ return
ν€μλλ₯Ό μλ΅ν μ μλ€.
struct Rect {
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)
}
}
}
3. Read-Only Computed Properties
μ 2.1μ Case 1
μμ΄ κ°μ μμ λ₯Ό λ€μ 보μ. setter κ° νμ μκ³ getter λ§ νμν κ²½μ° μ΄λ₯Ό
Read-Only Computed Properties
λΌκ³ νλ©°, get
ν€μλμ μ€κ΄νΈ{ }
λ₯Ό μλ΅ν μ μλ€.
struct Classroom {
let subject: Subject
let maxStudents: Int
var applicant: Int = 0
var students: Int {
applicant > maxStudents ? maxStudents : applicant
}
enum Subject {
case Korean, English, Math, History, Science
}
}
3. Property Observers π©βπ»
1. Definition of Property Observers
Property Observers
λ Property μ κ°μ set
μ λ³νλ₯Ό κ΄μ°°νκ³ μ€νλλ€. μ κ°μ΄ κΈ°μ‘΄μ κ°κ³Ό κ°λλΌλ set μ΄
λ°μνλ κ² μμ²΄λ‘ trigger λκΈ° λλ¬Έμ νΈμΆλλ€.
1 ) Attach Observers
Property μ Observers
λ₯Ό λΆμΌ μ μλ κ³³μ λ€μκ³Ό κ°λ€.
- Stored Properties
- μμλ Stored Properties
- μμλ Computed Properties
μμλ Properties μ Property Observers λ₯Ό λΆμΌ λλ
overriding
μ μ΄μ©νλ€.
μμλμ§ μμ Computed Properties λ Property Observers λ₯Ό μ¬μ©ν μ μμΌλ―λ‘, λμμΌλ‘ Computed Properties μ setter λ₯Ό μ¬μ©ν΄ μΌμ λΆλΆ μ μ¬νκ² κ΅¬ννλ λ°©λ²μ΄ μλ€.
2 ) willSet & didSet
Computed Properties λ setter
μ getter
λΌλ 2κ°μ§ μ΅μ
μ΄ μ‘΄μ¬νλ€.
Property Observers λ willSet
κ³Ό didSet
μ΄λΌλ 2κ°μ§ μ΅μ
μ΄ μ‘΄μ¬νλ€.
- willSet : κ°μ΄ μ μ₯λκΈ° μ§μ μ νΈμΆλλ©°, Parameters λ₯Ό μλ΅νλ©΄ κΈ°λ³Έκ°μΌλ‘
newValue
λ₯Ό μ¬μ©νλ€. - didSet : κ°μ΄ μ μ₯λ μ§νμ νΈμΆλλ©°, Parameters λ₯Ό μλ΅νλ©΄ κΈ°λ³Έκ°μΌλ‘
oldValue
λ₯Ό μ¬μ©νλ€.
Syntax
class SomeClass {
var someProperty: Type = defaultValue {
willSet {
// observer definition for willSet goes here
}
didSet {
// observer definition for didSet goes here
}
}
}
Lazy Stored Properties λλ Computed Properties μ λ§μ°¬κ°μ§λ‘ λ°λμ
var
ν€μλμ ν¨κ» μ¬μ©νλ€. λν μ΄κΈ°κ°μ λ°λμ μ μν΄μΌνλ©°, λ‘μ§μ Trailing Closures λ₯Ό μ΄μ©ν΄ μ μνλ€.Lazy Stored Properties μ Computed Properties, Property Observers λ Syntax κ° μ μ¬ν΄ ν·κ°λ¦¬κΈ° μ½λ€. λ€κ°μ΄ λκ³ λΉκ΅ν΄λ³΄λ©΄ λ€μκ³Ό κ°μ μ°¨μ΄λ₯Ό 보μΈλ€.
- Lazy Stored Properties
lazy var someProperty = { return // property definition goes here }() lazy var anotherProperty = SomeClass() // or SomeStructure()
Lazy Stored Properties λ Closures λλ Classes μ Initializers μ
()
λ₯Ό λΆμ¬ μ€ννκ³ λ°νλ κ°μ λ°λ‘ λ³μμ μ μ₯νλλ‘ λμ΄μλ€. λμ μ μ₯μ μ§μ°μν€κΈ° μν΄lazy
modifier λ₯Ό μμ±νλ€.
- Computed Properties
var someProperty: SomeType { get { return // property definition for getter goes here } set (parameterName) { // property definition for setter goes here } }
Computed Properties λ κΈ°λ³Έκ° μ μ₯ μμ΄
get
,set
μ λ©μλλ‘ κ°λ Trailing Closures λ₯Ό μμ±ν΄ μ μνλ€. Lazy Stored Properties μ λ¬λ¦¬()
λ₯Ό μμ±νμ§ μλλ€.
- Property Observers
var someProperty: Type = defaultValue { willSet { // observer definition for willSet goes here } didSet { // observer definition for didSet goes here } }
κΈ°λ³Έκ°μ μ μ₯
νκ³ λ€μwillSet
,didSet
μ λ©μλλ‘ κ°λ Trailing Closures λ₯Ό μμ±ν΄ μ μνλ€.
3 ) Initializer of subclass
Property Observers μ willSet, didSet μ Initializers μ μν΄ Instance κ° μμ±λ λλ μλνμ§ μλλ€. Initializers μ μν΄ Instance κ° μμ±λκ³ λ μ΄νμ Observers κ° μλνλ€.
λ°λΌμ λ€μκ³Ό κ°μ κ³Όμ μ κ±°μΉκ² λλ€.
- Subclass κ° μμ μ Properties μ μμ±μ λͺ¨λ μ€μ ν ν Superclass μ Initializers λ₯Ό νΈμΆνλ€.
- Superclass κ° μμ μ Designated Initializers λ₯Ό μ΄μ©ν΄ Initialization μ μννλ€. μ΄λ Superclass μμ μ΄ κ°κ³ μλ Observers λ μλνμ§ μλλ€. μ΄λ‘μ¨ Phase 1 μ΄ μ’ λ£λλ€.
- μ΄μ
Phase 2
κ° μ§νλκ³ Subclass μ Initializers κ° Superclass μ Properties λ₯Ό μμ νλ€. μ΄λ ν΄λΉ Properties μ Observers κ° λΆμ΄μλ€λ©΄willSet
,didSet
μ΄ μλνλ€.
2. Property Observer Examples
μλ κ±Έμμ λ°μ΄ν°λ₯Ό μ μ₯νλ StepCounter κ° μλ€.
class StepCounter {
var totalSteps: Int = 0 {
willSet {
if newValue > totalSteps {
print("About to set totalSteps to \(newValue)")
} else {
print("Please check your step data")
return
}
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps, totalStep is now \(totalSteps)")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
About to set totalSteps to 200
Added 200 steps, totalStep is now 200
200보λ₯Ό μ μ₯νλ€. μ΄κΈ°κ°μ 0μ΄λ―λ‘ (200 - 0)μ κ³μ°ν΄ β200λ³΄κ° μΆκ°λμκ³ , νμ¬ μ΄ κ±Έμμλ 200보βμμ μΆλ ₯νλ€.
stepCounter.totalSteps = 100
Please check your step data
μμμ μ μ₯ν μ 체 κ±Έμμκ° 200보μλλ° μ 체 κ±Έμμλ₯Ό 100보 μ μ₯νλ €κ³ νλ€. willSet μ΄ μ΄λ₯Ό κ±°μ νκ³ λ©μμ§λ₯Ό λ¨κ²ΌμΌλ©°, didSet μ μΌμΉνλ μ‘°κ±΄μ΄ μμ΄ μ’ λ£λμλ€.
stepCounter.totalSteps = 360
About to set totalSteps to 360
Added 260 steps, totalStep is now 360
λ€μ 360보λ₯Ό μ μ₯νλ μ μμ μΌλ‘ μ μ₯μ΄ λμλ€. νμ§λ§ μ΄μ μ μ μ₯ν 200보λ₯Ό κΈ°μ€μΌλ‘ (360-200)μ ν΄μ β160λ³΄κ° μΆκ°λμκ³ , νμ¬ μ΄ κ±Έμμλ 360보βμμ μΆλ ₯ν κ²μΌλ‘ μμνμΌλ κ±°μ λ©μμ§λ₯Ό λ¨κ²Όλ 100λ³΄κ° μ€μ λ‘λ μ μ₯λμ΄ β260λ³΄κ° μΆκ°λμκ³ , νμ¬ μ΄ κ±Έμμλ 360보βλΌκ³ μΆλ ₯νλ€.
μμμ willSet μ΄ κ±°μ λ©μμ§λ₯Ό λ¨κΈ°λ©° return
μ νμ§λ§ μ€μ λ‘ κ°μ μ μ₯μ λ§μ§λ λͺ»νκΈ° λλ¬Έμ΄λ€.
willSet
μ κ°μ μ μ₯νκΈ° μ§μ μ νλμ μ μν μ μμ λΏ κ°μ μ μ₯νλ νμ μ체λ₯Ό μ μ΄νμ§λ λͺ»νλ€!!
μ Class
λ₯Ό κ³ μ³ Validation Check
κ° κ°λ₯νλλ‘ ν΄λ³΄μ.
class StepCounter {
var totalSteps: Int = 0 {
willSet {
if newValue > totalSteps {
print("About to set totalSteps to \(newValue)")
}
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps, totalStep is now \(totalSteps)")
} else {
print("Please check your step data")
totalSteps = oldValue
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
print("--------------------------------------")
stepCounter.totalSteps = 100
print("--------------------------------------")
stepCounter.totalSteps = 360
About to set totalSteps to 200
Added 200 steps, totalStep is now 200
--------------------------------------
Please check your step data
--------------------------------------
About to set totalSteps to 360
Added 160 steps, totalStep is now 360
μ΄λ²μλ 360보λ₯Ό μ μ₯ν λ κΈ°μ‘΄μ 200보μμ 160λ³΄κ° μΆκ°λμλ€.
Validation Check
κ° νμνλ€λ©΄Property Observers
λ μ ν©νμ§ μλ€. μ μμ μμ λ³Ό μ μλ―μ΄ κ°μ μ μ₯νλ νμ μ체λ₯Ό μ μ΄νμ§λ λͺ» νκ³ μ μ₯ ν λ€μ κΈ°μ‘΄ κ°μΌλ‘ λ‘€λ°±νλ κ²μ΄κΈ° λλ¬Έμ΄λ€.λν
Computed Properties
λ₯Ό μ΄μ©νλ κ² μμ μκΈ° μμ μκ² μ μ©νλ©΄ κ°ν μν μ°Έμ‘°λ₯Ό μμ±νλ―λ‘ μ ν©νμ§ μλ€. λ°λΌμ Validation Check κ° νμν κ²½μ° λ¨μνκ³ κ³΅ν΅νκ° κ°λ₯νλ€λ©΄Property Wrappers
λ₯Ό μ¬μ©νκ³ , κ·Έλ μ§ μμ κ²½μ°setter
λ©μλλ₯Ό λ³λλ‘ μ μνλ κ²μ΄ μ’λ€.
λ§μ§λ§μΌλ‘ Property Observers λ₯Ό μ¬μ©ν λλ λ€μ κ²½μ°λ₯Ό μ‘°μ¬ν΄μΌνλ€.
Observers
κ° λΆμ Properties λ₯Ό ν¨μμ In-Out Parametersλ‘ μ λ¬νλ©΄,willSet
κ³ΌdidSet
μ νμ νΈμΆλλ€. μ΄λIn-Out Parameters
κ°Copy-in Copy-out Memory Model
μ μν΄ ν¨μκ° μ’ λ£λ λ νμ κ°μ λ€μ μ μ₯νκΈ° λλ¬Έμ΄λ€.
4. Property Wrappers π©βπ»
1. Property Wrappers
1 ) Syntax
Property Wrappers
λ Properties λ₯Ό μ μνλ μ½λμ μ μ₯λλ λ°©λ²μ κ΄λ¦¬νλ μ½λ μ¬μ΄μ λΆλ¦¬λ layer(κ³μΈ΅)
μ
μΆκ°νλ€.
μλ₯Ό λ€μ΄ Thread-Safe
κ²μ¬λ₯Ό μ 곡νλ Properties, λλ κΈ°λ³Έ λ°μ΄ν°λ₯Ό Database μ μ μ₯
νλ Properties κ°
μλ κ²½μ° ν΄λΉ μ½λλ₯Ό λͺ¨λ Properties μ μμ±ν΄μΌνλ€. μ΄λ Property Wrappers
λ₯Ό μ¬μ©νλ©΄ μ½λλ₯Ό ν λ²λ§ μμ±νκ³
μ¬μ¬μ© ν μ μλ€.
Syntax
@propertyWrapper
struct SomeStructure {
private var someProperty: SomeType
var wrappedValue: SomeType {
get { someProperty }
set { someProperty = newValue }
}
}
Class
,Structure
,Enumeration
λ₯Ό μ΄μ©ν΄ μ μνλ©° 3κ°μ§ λΆλΆμΌλ‘ λλλ€@propertyWrapper
Annotation μ μ μΈprivate var
λ³μ μ μΈwrappedValue
λΌλ μ΄λ¦μ κ°λ Computed Propertyλ₯Ό μ μ
- Without
@propertyWrapper
Annotation
1 ~ 9 κΉμ§μ λ μλ₯Ό λ°μ ꡬꡬλ¨μ κ³μ°ν΄λ³΄μ. 1λ³΄λ€ μμ μλ 1λ‘, 9λ³΄λ€ ν° μλ 9λ‘ λ³κ²½νλλ‘ νλ€.
κΈ°μ‘΄μ λ°©μλλ‘ @propertyWrapper
μμ΄ explicit wrapping
μ νλ λ°©λ²λΆν° μμ보μ.
struct OneToNine {
private var number = 1
var wrappedValue: Int {
get { number }
set { number = max(min(newValue, 9), 1) }
}
}
// Explicit Wrapping
struct MultiplicationTable {
private var _left = OneToNine()
private var _right = OneToNine()
var left: Int {
get { _left.wrappedValue }
set { _left.wrappedValue = newValue }
}
var right: Int {
get { _right.wrappedValue }
set { _right.wrappedValue = newValue }
}
}
- With
@propertyWrapper
Annotation
@propertyWrapper
μμ΄ wrapping
μ νλ©΄ λͺ¨λ λ³μλ§λ€ λͺ
μμ μΌλ‘ μ½λλ₯Ό μμ±ν΄μΌνλ€. μ¦, μ μ§λ³΄μκ°
μ΄λ ΅λ€λ λ»μ΄λ€.
μ°λ¦¬λ μ΄ λ¬Έμ λ₯Ό @propertyWrapper
λ₯Ό ν΅ν΄ μλμ κ°μ΄ ν΄κ²°ν μ μλ€.
@propertyWrapper
struct OneToNine {
private var number = 1
var wrappedValue: Int {
get { number }
set { number = max(min(newValue, 9), 1) }
}
}
struct MultiplicationTable {
@OneToNine var left: Int
@OneToNine var right: Int
}
var multiplication = MultiplicationTable()
multiplication.left = 7
multiplication.right = 8
print("\(multiplication.left) x \(multiplication.right) = \(multiplication.left * multiplication.right)")
// Prints "7 x 8 = 56"
multiplication.left = 10
multiplication.right = 5
print("\(multiplication.left) x \(multiplication.right) = \(multiplication.left * multiplication.right)")
// Prints "9 x 5 = 45"
μ°Έκ³ λ‘ Observers
μ Wrappers
λ λμμ μ¬μ©νμ§ λͺ»νλ κ²μΌλ‘ 보μΈλ€.
Can I implement a property observer in a property wrapper structure?
2. Setting Initial Values for Wrapped Properties
μ μ½λλ Property Wrappers κ° μ΄κΈ°κ°μ νλμ½λ©ν΄ μ μ₯νκ³ μλ€. λ°λΌμ λ€λ₯Έ μ΄κΈ°κ°μ μ§μ ν μ μμ΄ μ μ°μ±μ΄ λ¨μ΄μ§λ€.
μ°λ¦¬λ μ΄ λ¬Έμ λ₯Ό Initializer
λ₯Ό μ΄μ©ν΄ ν΄κ²°ν μ μλ€.
μ¬κ°νμ λ³μ κΈΈμ΄λ₯Ό μ μνλ LengthOfSide κ° λ€μκ³Ό κ°μ΄ μ μλμ΄μλ€.
@propertyWrapper
struct LengthOfSide {
private var maximum: Int
private var length: Int
var wrappedValue: Int {
get { length }
set { length = min(newValue, maximum) }
}
init() {
maximum = 10
length = 0
}
init(wrappedValue: Int) {
maximum = 10
length = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
length = min(wrappedValue, maximum)
}
}
- init() : arguments κ° μμ΄ μ΄κΈ°ν νλ©΄ κΈ°λ³Έκ°μΌλ‘ μ΅κ³ κΈΈμ΄λ 10, λ³μ κΈΈμ΄μ μ΄κΈ°κ°μ 0μΌλ‘ Structure λ₯Ό μ΄κΈ°ννλ€.
- init(wrappedValue:) : arguments λ₯Ό νλλ§ λ°μ wrappedValue λ₯Ό λ³μ κΈΈμ΄μ μ΄κΈ°κ°μΌλ‘ νκ³ μ΅κ³ κΈΈμ΄λ 10μΌλ‘ Structure λ₯Ό μ΄κΈ°ννλ€.
- init(wrappedValue:maximum:) : λ³μ μ΅κ³ κΈΈμ΄μ μ΄κΈ°κ°μ λͺ¨λ λ°μ Structure λ₯Ό μ΄κΈ°ννλ€.
- init()
struct Rectangle {
@LengthOfSide var height: Int
@LengthOfSide var width: Int
}
var rectangle = Rectangle()
print(rectangle)
//Rectangle(_height: __lldb_expr_53.LengthOfSide(maximum: 10, length: 0),
// _width: __lldb_expr_53.LengthOfSide(maximum: 10, length: 0))
init()
μ μ΄μ©ν΄ μ΄κΈ°νλμ΄ μ¬κ°νμ μ΅λκ°μ 10, μ΄κΈ°κ°μ 0μΌλ‘ μ€μ λμλ€.
print("height: \(rectangle.height), width: \(rectangle.width)") // height: 0, width: 0
rectangle.height = 12
rectangle.width = 5
print("height: \(rectangle.height), width: \(rectangle.width)") // height: 10, width: 5
μ¬κ°νμ λμ΄μ λλΉλ μ΄κΈ°κ°μ μν΄ 0μ΄μκ³ , λμ΄λ₯Ό 12, λλΉλ₯Ό 5λ‘ μ€μ νλ€. νμ§λ§ Property Wrappers μ μν΄ λμ΄λ 10μΌλ‘ μ΅λκ°μ λμ§ μκ² μμ λμλ€.
Property Wrappers λ₯Ό μ΄κΈ°ν νλ λ°©λ²μ λ κ°μ§κ° μλ€
1 ) init(wrappedValue:maximum:)
첫 λ²μ§Έ λ°©λ²μ μμμ λ³Έ κ²μ²λΌ Property Wrappers μ Initializers
λ₯Ό μ¬μ©νλ κ²μ΄λ€.
struct NarrowRectangle {
@LengthOfSide(wrappedValue: 15, maximum: 20) var height: Int
@LengthOfSide(wrappedValue: 3, maximum: 5) var width: Int
}
var narrowRectangle = NarrowRectangle()
print(narrowRectangle)
//NarrowRectangle(_height: __lldb_expr_69.LengthOfSide(maximum: 20, length: 15),
// _width: __lldb_expr_69.LengthOfSide(maximum: 5, length: 3))
print("height: \(narrowRectangle.height), width: \(narrowRectangle.width)") // height: 10, width: 5
height λ₯Ό wrapping ν LengthOfSide instance λ Initializer
LengthOfSide(wrappedValue: 15, maximum: 20)
λ₯Ό νΈμΆν΄ μμ±λμκ³ , weight λ₯Ό wrapping ν LengthOfSide
instance λ Initializer
LengthOfSide(wrappedValue: 3, maximum: 5)
λ₯Ό νΈμΆν΄ μμ±λμλ€.
2 ) Initial Values
λ λ€λ₯Έ λ°©λ²μΌλ‘, wrappedValue
λ₯Ό Properties μ Initial Values
λ₯Ό μ¬μ©ν΄ μ΄κΈ°ννλ κ²μ΄λ€.
struct HugeRectangle {
@LengthOfSide(maximum: 20) var height: Int = 20
@LengthOfSide(maximum: 20) var width: Int = 25
}
var hugeRectangle = HugeRectangle()
print(hugeRectangle)
//HugeRectangle(_height: __lldb_expr_74.LengthOfSide(maximum: 20, length: 20),
// _width: __lldb_expr_74.LengthOfSide(maximum: 20, length: 20))
print("height: \(hugeRectangle.height), width: \(hugeRectangle.width)") // height: 20, width: 20
init(maximim:)
μ΄λΌλ Initializer
κ° μμμλ λΆκ΅¬νκ³ , init(wrappedValue:maximum:)
κ³Ό λμΌνκ²
μλν¨μ μ μ μλ€.
3. Projecting a Value From a Property Wrapper
μ°μ Projection Mapping
μ΄λΌλ μ©μ΄λ₯Ό μμ보μ.
νλ‘μ μ 맀ν(Projection Mapping)μ λμλ¬Όμ νλ©΄μ λΉμΌλ‘ μ΄λ£¨μ΄μ§ μμμ ν¬μ¬νμ¬ λ³νλ₯Ό μ€μΌλ‘μ¨, νμ€μ μ‘΄μ¬νλ λμμ΄ λ€λ₯Έ μ±κ²©μ κ°μ§ κ²μ²λΌ 보μ΄λλ‘ νλ κΈ°μ μ΄λ€.
μ¦, Projecting a Value From a Property Wrapper λ Property Wrapper
λ₯Ό μ΄μ©ν΄ νμ¬μ Instance μ
μ‘΄μ¬νμ§ μλ κ°μ μ‘΄μ¬νλ λμμΈ κ²μ²λΌ 보μ΄λλ‘ νλ κ²μ΄λ κ²μ μ μΆν μ μλ€.
κ·Έλ¦¬κ³ Apple Developer Documentation μ projectedValue
λ‘ κ²μμ νλ©΄ λ€μν κ³³μμ μ¬μ©λλ κ²μ
λ³Ό μ μλλ°, λ€μ λ λ§ν¬(Link 1, Link 2)λ‘λΆν° μ μΆν΄λ³΄λ©΄
getter
,setter
λ₯Ό μ΄μ©ν΄ μλνλ€super
μͺ½value
λ₯Όsub
μͺ½μ λ ΈμΆμν¨λ€. μ¦, κΈ°λ³ΈμΌλ‘ λ ΈμΆλμ§ μλ μμhierarchy
μ μ 보λ₯Ό μ κ·Όνκ² νλ€
λ‘ μμ½ν μ μμ κ² κ°λ€.
λ€μ Swift.orgλ‘ λμμ보μ. Property Wrappers
λ wrappedValue
μΈμλ projectedValue
μ μλ₯Ό
μ΄μ©ν΄ μΆκ°μ μΈ κΈ°λ₯μ λ
ΈμΆν μ μλ€κ³ μ€λͺ
νλ λΆλΆμ μ΄λμ λ μ΄ν΄ν μ μλ€.
Apple Developer Documentation μ projectedValue λ₯Ό μ μνλ λ°©λ²μ 보면 μ΄λ€ Swift Library κ·Έλ£Ήμ μν΄μλμ§μ λ°λΌ μ½λ© ννκ° λ€λ₯Έ κ²μΌλ‘ 보μΈλ€. μ°μ Swift.org μ μμ λ₯Ό κΈ°μ€μΌλ‘ μ€λͺ νλ©΄ Syntax λ μλμ κ°λ€.
Syntax
@propertyWrapper
struct SomeStructure {
private var someProperty: SomeType
private(set) var projectedValue: Bool
var wrappedValue: SomeType {
get { someProperty }
set { someProperty = newValue }
}
}
Class
,Structure
,Enumeration
λ₯Ό μ΄μ©ν΄ μ μνλ©° 3κ°μ§ λΆλΆμΌλ‘ λλλ€@propertyWrapper
Annotation μ μ μΈprivate(set) var
λ³μ μ μΈwrappedValue
λΌλ μ΄λ¦μ κ°λ Computed Propertyλ₯Ό μ μ
μμμ μ μν LengthOfSide μ projectedValue
λ₯Ό μΆκ°ν΄ λ€μ μ μν΄λ³΄μ.
@propertyWrapper
struct LengthOfSide {
private var maximum: Int
private var length: Int
private(set) var projectedValue: Bool = false
var wrappedValue: Int {
get { length }
set {
if newValue > maximum {
length = maximum
projectedValue = true
} else {
length = newValue
projectedValue = false
}
}
}
init() {
maximum = 10
length = 0
}
init(wrappedValue: Int) {
maximum = 10
length = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
length = min(wrappedValue, maximum)
}
}
struct HugeRectangle {
@LengthOfSide(wrappedValue: 20, maximum: 20) var height: Int
@LengthOfSide(maximum: 20) var width: Int = 25
}
var hugeRectangle = HugeRectangle()
print(hugeRectangle)
//HugeRectangle(_height: __lldb_expr_74.LengthOfSide(maximum: 20, length: 20),
// _width: __lldb_expr_74.LengthOfSide(maximum: 20, length: 20))
print("height: \(hugeRectangle.height), width: \(hugeRectangle.width)") // height: 20, width: 20
HugeRectangle Structure λ‘λΆν° μμ±ν hugeRectangle Instance λ₯Ό μΆλ ₯ν΄λ³΄μμΌλ κΈ°μ‘΄μ LengthOfSide μ λ€λ₯Όκ² μμ΄ λ³΄μΈλ€.
print(hugeRectangle.height) // 20
print(hugeRectangle.$height) // false
print(hugeRectangle.width) // 20
print(hugeRectangle.$width) // false
νμ§λ§ μμ $
μ¬μΈμ λΆμ¬μ£Όμ Instance λ₯Ό μ μν λμλ μκ³ , μΆλ ₯ν λμλ μλ κ°μ΄ λνλλ€.
μ΄ κ°μ HugeRectangle μ Properties κ° μλ LengthOfSide μ Properties
λ€!
νμ§λ§ λ§μΉ hugeRectangle Instance μ Properties μΈ κ² μ²λΌ ν¬μ
λμ΄ λ³΄μ¬μ§λ€!!
μ΄μ wrappedValue
λ₯Ό μ΄μ©ν΄ κ°μ μ΄κ³Όνλλ‘ μ μ₯ν΄λ³΄μ.
hugeRectangle.width = 30
print(hugeRectangle.width) // 20
print(hugeRectangle.$width) // true
κ°μ΄ μ΄κ³Όλμκ³ , setter
μ μ μνλλ‘ width λ maximum κ°μΌλ‘ 보μ ν΄ μ μ₯λμλ€. κ·Έλ¦¬κ³ projectedValue
λ
true
λ‘ λ³κ²½λμλ€.
Projecting
μ Initializers μμλ μλνμ§ μλλ€.@LengthOfSide(maximum: 20) var width: Int = 25
μ½λλ₯Ό 보면 λ§μΉ 25 λΌλ κ°μ΄ Property Wrapper μset
μ νΈμΆν΄ μλν κ² κ°μ§λ§ μ΄κ²μ@LengthOfSide(wrappedValue: 25, maximum: 20)
μ μμ ν λμΌνκ² μλν λΏμ΄λ€. μ¦, Instance κ° μμ±λ μ΄ν μ μμ μΌλ‘ μλνλ€.
projectedValue λ λ€μκ³Ό κ°μ΄ Class, Structure, Enumeration μ λ΄λΆ context
μμλ μ¬μ©ν μ μλ€.
enum Size {
case small, large
}
struct SizedRectangle {
@LengthOfSide var height: Int
@LengthOfSide 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
}
}
var rectangle = SizedRectangle()
var resizeWasCalibrated = rectangle.resize(to: .small)
print(rectangle.height, rectangle.$height) // 10 false
print(rectangle.width, rectangle.$width) // 10 true
print(resizeWasCalibrated) // true
5. Global and Local Variables π©βπ»
- Global Variables: Functions, Methods, Closures, Type Context μΈλΆμ μ μλ λ³μλ₯Ό μλ―Έ
- Local Variables: Functions, Methods, Closures Context λ΄λΆμ μ μλ λ³μλ₯Ό μλ―Έ
1. Stored Variables
Stored Variables
λ Stored Properties
μ²λΌ κ°μ μ μ₯νκ³ κ²μνλ κ²μ μ 곡νλ€.
Global Constants μ Global Variables λ νμ
lazily
νκ² κ³μ°λλ€. μ΄λ Lazy Stored Properties μ μ μ¬νλ€. λ¨, Lazy Stored Properties μ λ€λ₯Έ μ μlazy
modifier λ₯Ό λΆμΌ νμκ° μλ€.λ°λ©΄μ Local Constants μ Local Variables λ μ λ
lazily
νκ² κ³μ°λμ§ μλλ€.
2. Computed Variables
Global Variables μ Local Variables λͺ¨λ Computed
λ₯Ό μ¬μ©ν μ μλ€.
3. Variable Observers
Global Variables μ Local Variables λͺ¨λ Observer
λ₯Ό μ¬μ©ν μ μλ€.
4. Variable Wrappers
Property Wrappers
λ Local Stored Variables
μλ§ μ μ© κ°λ₯νλ€.
Global Variables λλ Computed Variables μλ μ μ©ν μ μλ€.
func someFunction() {
@LengthOfSide var length: Int
print(length) // 0
length = 5
print(length) // 5
length = 12
print(length) // 10
}
someFunction()
6. Type Properties π©βπ»
C λ Objective-C μμ static constants, static variables λ₯Ό μ μνκΈ° μν΄ Global Static Variables
λ₯Ό μ¬μ©νλ€.
νμ§λ§ Swift λ λΆνμνκ² μ μμΌλ‘ μμ±λλ Global Static Variables μ μ μ λ³μ μ€μΌ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄
Type Properties
λ₯Ό μ 곡νλ€. Type Properties λ Swift Types κ° μ μλλ { }
λ΄λΆ context
λ²μ
λ΄μ μ μλλ©°, κ·Έ Scope
λ²μ λ΄μμλ§ μ¬μ© κ°λ₯νλ€.
1. Type Property Syntax
Global Static Variables μ λ§μ°¬κ°μ§λ‘ Properties μμ static
ν€μλλ₯Ό μ¬μ©νλ€.
λ¨, Classes μ κ²½μ° Computed Properties λ₯Ό Subclass μμ overriding
μ νμ©νλ €λ©΄ Superclass μμ
static
keyword λμ class
keyword λ₯Ό μ¬μ©νλ€.
Type Properties
λ μ μν λ λ°λμInitiate Value
λ₯Ό ν¨κ» μ μν΄μΌνλ€.
- Structures
struct SomeStructure {
static var someTypeProperty = "Initiate Value"
static var computedTypeProperty: Int {
return 1
}
}
- Enumerations
enum SomeEnumeration {
static var someTypeProperty = "Initiate Value"
static var computedTypeProperty: Int {
return 6
}
}
- Classes
class SomeClass {
static var someTypeProperty = "Initiate Value"
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
computedTypeProperties λ
static
keyword λ₯Ό μ¬μ©νΈμ§λ§ overrideableComputedTypeProperty λclass
keyword λ₯Ό μ¬μ©ν΄ Subclass μμ overriding νλ κ²μ νμ©νλ€.
2. Querying and Setting Type Properties
1 ) Difference between Type Properties and Properties
μλμ κ°μ΄ AnotherStructure λ₯Ό μ μνλ€.
struct AnotherStructure {
static var storedTypeProperty = "Apple"
var storedProperty = "Pear"
static var computedTypeProperty: Int { 1 }
var computedProperty: Int { 10 }
}
- Type Properties
print(AnotherStructure.storedTypeProperty) // Apple
print(AnotherStructure.computedTypeProperty) // 1
AnotherStructure.storedTypeProperty = "Melon"
print(AnotherStructure.storedTypeProperty) // Melon
Type Properties λ Instance Properties μ λμΌνκ² dot Syntax
λ₯Ό μ΄μ©ν΄ κ°μ μ κ·Όνκ³ κ°μ μ μ₯νλ€.
- Instance Properties
var anotherStructure = AnotherStructure()
print(anotherStructure.storedProperty) // Pear
print(anotherStructure.computedProperty) // 10
anotherStructure.storedProperty = "Watermelon"
print(anotherStructure.storedProperty) // Watermelon
Instance Properties λ Instance μμ± μ μλ μ κ·Όν μ μλ€.
var theOtherStructure = AnotherStructure()
print(theOtherStructure.storedProperty) // Pear
print(AnotherStructure.storedTypeProperty) // Melon
μμμ anotherStructure κ° Instance Properties
λ₯Ό μμ ν κ²μ theOtherStructure μ μν₯μ
λ―ΈμΉμ§ μλλ€. νμ§λ§ AnotherStructure
μ Type Properties
λ₯Ό μμ ν κ²μ Type
μμ²΄κ° μμ λμκΈ°
λλ¬Έμ Apple μ΄ μλ Melon μ μΆλ ₯νλ€.
2 ) Audio Channel Examples
struct AudioChannel {
static let thresholdLevel = 10
static var maxInputLevelForAllChannels = 0
var currentLevel: Int = 0 {
didSet {
if currentLevel > AudioChannel.thresholdLevel {
currentLevel = AudioChannel.thresholdLevel
}
if currentLevel > AudioChannel.maxInputLevelForAllChannels {
AudioChannel.maxInputLevelForAllChannels = currentLevel
}
}
}
}
- thresholdLevel : μ€λμ€κ° κ°μ§ μ μλ λ³Όλ₯¨ μ΅λκ°μ μ μ (μμ 10)
- maxInputLevelForAllChannels : AudioChannel Instance κ° λ°μ μ΅λ μ λ ₯κ°μ μΆμ (0μμ μμ)
- currentLevel : νμ¬μ μ€λμ€ λ³Όλ₯¨μ κ³μ°μ ν΅ν΄ μ μ
var leftChannel = AudioChannel()
var rightChannel = AudioChannel()
μ’μ° μ±λμ κ°κ° Instnace λ‘ μμ±νλ€.
leftChannel.currentLevel = 7
print(leftChannel.currentLevel) // 7
print(AudioChannel.maxInputLevelForAllChannels) // 7
μΌμͺ½ λ³Όλ₯¨μ 7λ‘ μ¬λ¦¬μ μΌμͺ½ μ±λμ λ³Όλ₯¨μ΄ 7λ‘, Type Property maxInputLevelForAllChannels μμ 7λ‘ μ μ₯λμλ€.
rightChannel.currentLevel = 11
print(rightChannel.currentLevel) // 10
print(AudioChannel.maxInputLevelForAllChannels) // 10
μ΄λ²μ μ€λ₯Έμͺ½ λ³Όλ₯¨μ 11λ‘ μ¬λ¦¬μ μ΅λ λ 벨 μ νμ μν΄ 10μΌλ‘ μ μ₯λκ³ , μ΄μ λ°λΌ κ·Έ λ€μ if statement μμ maxInputLevelForAllChannelsκ° 10μΌλ‘ μ μ₯λμλ€.
Reference
- βProperties.β The Swift Programming Language Swift 5.7. accessed Nov. 21, 2022, Swift Docs Chapter 9 - Properties.
- βProjected Value.β Apple Developer Documentation. accessed Nov. 25, 2022, Apple Developer Documentation - Swift/Swift Standard Library/../projectedValue.
- βProjected Value.β Apple Developer Documentation. accessed Nov. 25, 2022, Apple Developer Documentation - Swift/Swift UI/../projectedValue.
- βνλ‘μ μ 맀ν.β Wikipedia. Mar. 6, 2022, νλ‘μ μ 맀ν.