์ ์ฅ๋ ์์, ๋ณ์.
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) ์ฒ๋ผ
// ์์ ์๋ก์ด ๋ณ์๋ฅผ ํ ๋นํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅ.
์ฌ์ฉ๋๊ธฐ ์ ๊น์ง ์ด๊ธฐ๊ฐ์ด ๊ณ์ฐ๋์ง ์๋ ํ๋กํผํฐ.
์ด๊ธฐํ ์๋ฃ ํ์๋ ์ด๊ธฐ๊ฐ์ด ์์ ์ ์๊ธฐ ๋๋ฌธ์ 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 ํ๋กํผํฐ์ ์ ๊ทผํ๊ฒ ๋๋ฉด, ์ฌ๋ฌ๋ฒ ์ด๊ธฐํ ๋ ์๋ ์๋ค.
๊ฐ์ ์ค์ง์ ์ผ๋ก ์ ์ฅํ์ง ์๊ณ , ๋ค๋ฅธ ํ๋กํผํฐ์ ๊ฐ์ ๊ฐ์ ์ ์ผ๋ก ๊ฐ์ ธ์์ ์ค์ . 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
}
๐ ๋ฉ์๋ ๋์ ์ฐ๋ ์ด์ : ์ง๊ด์ ์ด๊ณ , ๋๊ฐ๋ ๋ง๋ค ํ์๊ฐ ์๋ค.
๐ ๋จ์ ? : ์ฐ๊ธฐ ์ ์ฉ ํ๋กํผํฐ๋ ์์ฑํ ์ ์๋ค.
ํ๋กํผํฐ์ ๊ฐ์ด ๋ณ๊ฒฝ๋๋์ง ๊ด์ฐฐํ๊ณ ์๋ตํ๋ค.
์๋ก์ด ๊ฐ๊ณผ ํ์ฌ ๊ฐ์ด ๊ฐ์๋ ํ๋กํผํฐ์ ๊ฐ์ด ์ค์ ๋ ๋ ํธ์ถ๋๋ค.
์์ ์ถ๊ฐํ ์ ์๋ค. (์ ์ญ ๋ณ์์ ์ ์ํ ๊ณ์ฐ ํ๋กํผํฐ์์๋ ๋ถ๊ฐ๋ฅ)
์ฃผ์ : ์ฌ๊ธฐ์ ์๊ธฐ ์์ ์ ๋ค์ 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 ์ด ๋ชจ๋ ํธ์ถ๋๋ค.
๊ฐ์ด ์ค์ ๋ก ์ ์ฅ๋์ด ์๋ ํ๋กํผํฐ, ๊ฐ์ ๊ด๋ฆฌํ๋ ํ๋กํผํฐ๋ฅผ ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ค. ๋ก์ง์ด ์์ฃผ ์ฐ์ด๊ณ ์ฌ์ฌ์ฉ์ฑ์ด ์๋ค๋ฉด ์ด๋ ๊ฒ ๊ด๋ฆฌํด์ฃผ์.
@๊ตฌ์กฐ์ฒด์ด๋ฆ
ํค์๋๋ฅผ ๋ถ์ฌ์ ์ฌ์ฉํ๋ค.@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 }
}
}
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 ๋ค๋ฃจ๊ฒ ํ๋๋ฐ, ๋ง์ด ๊ฒน์น๋ฏ๋ก ์ด ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ฉด ์ข์๋ฏ.
์ ์ญ ์์, ๋ณ์๋ ํญ์ lazy ๋ก ๊ณ์ฐ๋๋ค.
์ธ์คํด์ค๋ง๋ค ์์ฑ๋๋ ํ๋กํผํฐ์ ๋ค๋ฅด๊ฒ, ํ์
ํ๋์ ์์ฑ๋๋ ํ๋กํผํฐ.
๊ธฐ๋ณธ๊ฐ์ ํญ์ ์ค์ผํ๊ณ , ๊ธฐ๋ณธ์ ์ผ๋ก lazy ๋ก ๋์ํ๋ค.
๐ ํ์ง๋ง, ๋ค์ค ์ค๋ ๋ ํ๊ฒฝ์์๋ ์ฌ๋ฌ๋ฒ ์ด๊ธฐํ๋์ง ์๋๋ค.
์ ์ฅ / ๊ณ์ฐ ํ๋กํผํฐ๋ก ๋ชจ๋ ์ ์ ๊ฐ๋ฅ
์ ์ํ๋ ๋ฌธ์ฅ ์์ static ํค์๋๋ฅผ ๋ถ์ฌ์ ์ฌ์ฉํ๋ค.
struct UserInfo {
static var uuid: String {
return UUID().uuidString
}
static var name: String = "์ด๊ธฐ๊ฐ"
}
print(UserInfo.uuid)
+) struct ๋ณด๋ค๋ enum ์์ ๋ง์ด ์ฌ์ฉํ๋ค. ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ง ์๊ณ ์ฌ์ฉํ๋ ค๊ณ . enum ์ ์ด๊ธฐ์๊ฐ ์์ผ๋๊น!!
๐ ๋ชจ๋ ์ธ์คํด์ค๊ฐ ๊ณตํต
์ผ๋ก ์ฌ์ฉํ๋ ๊ฐ์ ์ฌ์ฉํ๋ค.
๐ Stored, Computed ํ๋กํผํฐ๋ก ์ ์ ๊ฐ๋ฅ
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
์ฐธ๊ณ
https://bbiguduk.gitbook.io/swift/language-guide-1/properties
์ผ๊ณฐ์ Swift5 Programming