Potato
์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์žก๋‹ˆ๋‹ค?๐Ÿฅ” ^___^ ๐Ÿ˜บ github ๋ฐ”๋กœ๊ฐ€๊ธฐ ๐Ÿ‘‰๐Ÿป

Swift/Swift Documents

[Swift] ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ (10) - Properties (์ €์žฅ ํ”„๋กœํผํ‹ฐ, ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ, ํƒ€์ž… ํ”„๋กœํผํ‹ฐ, ์˜ต์ €๋ฒ„, wrapper)

๊ฐ์ž ๐Ÿฅ” 2022. 2. 25. 23:02
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์ž์ž…๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ property์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ ๊ฐœ๋…์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ฐธ ๋ชจํ˜ธํ•˜๊ณ  ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š์•˜๋˜ ๋ถ€๋ถ„์ด ๋งŽ์•˜๋Š”๋ฐ์š”, ์ด๋Ÿฐ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ๋Š” ์ถ”ํ›„์— ํ”„๋กœํผํ‹ฐ ์ •๋ณตํ•˜๊ธฐ ํฌ์ŠคํŒ…์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™์•„์š”. ์ผ๋‹จ ๊ธฐ์ดˆ๊ฐœ๋…์„ ์žก์€ ์ •๋ฆฌ๊ธ€ ์ •๋„๋กœ ๋ด์ฃผ์„ธ์š”! ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

Swift Document chap.10 Properties ๋ฐ”๋กœ๊ฐ€๊ธฐ

 

Properties — The Swift Programming Language (Swift 5.6)

Properties Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties a

docs.swift.org

 


Properties (ํ”„๋กœํผํ‹ฐ)

ํด๋ž˜์Šค๋‚˜ ๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐ์ฒด์˜ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ทธ ๋‚ด๋ถ€์— ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์˜ ์ƒํƒœ์— ๊ด€ํ•œ ์ •๋ณด๋ฅผ ๋งํ•œ๋‹ค.

ํ”„๋กœํผํ‹ฐ ์ข…๋ฅ˜

  • Stored Property (์ €์žฅํ”„๋กœํผํ‹ฐ)
    • ์ธ์Šคํ„ด์Šค์˜ ์ผ๋ถ€๋ถ„์œผ๋กœ์จ ์ƒ์ˆ˜์™€ ๋ณ€์ˆ˜ ๊ฐ’์„ ์ €์žฅํ•จ
    • ํด๋ž˜์Šค์™€ ๊ตฌ์กฐ์ฒด์—์„œ๋งŒ ์ œ๊ณตํ•จ
  • Computed Property (๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ)
    • ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š”๋ฐ ์“ฐ์ด๋Š” ํ”„๋กœํผํ‹ฐ
    • ํด๋ž˜์Šค, ๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐํ˜•์—์„œ ์ œ๊ณตํ•จ
  • Type Property (ํƒ€์ž… ํ”„๋กœํผํ‹ฐ)
    • ํ”„๋กœํผํ‹ฐ๋Š” ํƒ€์ž… ๊ทธ ์ž์ฒด์™€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ํƒ€์ž…ํ”„๋กœํผํ‹ฐ๋ผ๊ณ  ํ•จ

Property Observer (ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„)

  • ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ€์ง„ ๊ฐ’์˜ ๋ณ€ํ™”๋ฅผ ๊ด€์ฐฐํ•˜๊ธฐ ์œ„ํ•จ
  • ์ •์˜ํ•œ ํ”„๋กœํผํ‹ฐ๋‚˜ ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์ƒ์†๋ฐ›๋Š” ์ƒ์œ„ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

Property Wrapper

  • ํ”„๋กœํผํ‹ฐ wrapper๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ”„๋กœํผํ‹ฐ์˜ getter, setter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ.

 

Stored Properties (์ €์žฅ ํ”„๋กœํผํ‹ฐ)

ํด๋ž˜์Šค๋‚˜ ๊ตฌ์กฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค์˜ ์ผ๋ถ€๊ฐ€ ๋˜๋Š” ์ƒ์ˆ˜๋‚˜ ๋ณ€์ˆ˜์ด๋‹ค. let์œผ๋กœ ์„ ์–ธ๋˜์—ˆ๋ƒ var๋กœ ์„ ์–ธ ๋˜์—ˆ๋ƒ์— ๋”ฐ๋ผ ์ƒ์ˆ˜, ๋ณ€์ˆ˜ ์ค‘ ์–ด๋–ค ๊ฒƒ์œผ๋กœ ์„ ์–ธ ๋˜์—ˆ๋Š”์ง€ ์ •์˜๋œ๋‹ค.

๋˜ํ•œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ• ๋•Œ ์ €์žฅํ•  “๊ธฐ๋ณธ๊ฐ’ (Default Property Value)”๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌํ•œ ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋Š” initializer(์ƒ์„ฑ์ž)๋กœ ์ดˆ๊ธฐํ™” ์‹œํ‚ฌ ์ˆ˜ ๋„ ์žˆ๋‹ค. ์ƒ์„ฑ์ž์— ์˜ํ•ด ์ดˆ๊ธฐํ™” ๋  ๋•Œ๋Š” ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ƒ์ˆ˜๋กœ ์„ ์–ธ ๋˜์—ˆ๋‹ค๊ณ  ํ•ด๋„ ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

struct FixedLengthRange {
  var firstValue: Int
	let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// ์ด ๋ฒ”์œ„๋Š” ์ •์ˆ˜ ๊ฐ’ 0, 1, 2 ๋ฅผ ๋‚˜ํƒ€๋ƒ„
rangeOfThreeItems.firstValue = 6
// ์ด์ œ ๋ฒ”์œ„๋Š” ์ •์ˆ˜ ๊ฐ’ 6, 7, 8 ์„ ๋‚˜ํƒ€๋ƒ„

์œ„ ์ฝ”๋“œ๋Š” ์ƒ์„ฑ ํ›„์—๋Š” ๊ธธ์ด๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋Š” length ์ƒ์ˆ˜๋ฅผ ํฌํ•จํ•œ ๊ตฌ์กฐ์ฒด์ด๋‹ค.

 

Stored Properties of Constant Structure Instances

๊ตฌ์กฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์ˆ˜๋กœ ์ •์˜ํ–ˆ๋‹ค๋ฉด, ์ƒ์„ฑ๊ณผ ๋™์‹œ์— ์–ด๋–ค ํ”„๋กœํผํ‹ฐ๋„ ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค.

let rangeOfFourItems = FixedLengthRange(firstValue : 0, length: 4)
// ์ด ๋ฒ”์œ„๋Š” ์ •์ˆ˜ ๊ฐ’ 0, 1, 2, 3 ์„ ๋‚˜ํƒ€๋ƒ„

rangeOfFourItems.firstValue = 6. 
//ERROR!!!!
// ์ด๋Š”, firstValue ๊ฐ€ ๋ณ€์ˆ˜ ์†์„ฑ์ผ์ง€๋ผ๋„, ์—๋Ÿฌ๋ฅผ ๋ณด๊ณ ํ•  ๊ฒƒ์ž„

์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, firstValue๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์„ ์–ธํ•  ๋•Œ ๋ณ€์ˆ˜๋กœ ์„ ์–ธ๋˜์—ˆ์ง€๋งŒ, ๊ตฌ์กฐ์ฒด ์ธ์Šคํ„ด์Šค์ธ rangeOfFourItems ๋Š” ์ƒ์ˆ˜๋กœ ์„ ์–ธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— rangeOfFourItems๋Š” ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š” ์ด์œ ๋Š” ๊ตฌ์กฐ์ฒด๊ฐ€ ๊ฐ’ํƒ€์ž… ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ตฌ์กฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์ˆ˜๋กœ ์„ ์–ธํ•˜๊ฒŒ ๋˜๋ฉด ๋‚ด๋ถ€์˜ ํ”„๋กœํผํ‹ฐ๋“ค๋„ ๋ชจ๋‘ ์ƒ์ˆ˜๊ฐ€ ๋˜์–ด ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค.

 

ํ•˜์ง€๋งŒ, ์ฐธ์กฐํƒ€์ž…์ธ ํด๋ž˜์Šค์—์„œ๋Š” ์ด๊ฒƒ๊ณผ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚œ๋‹ค. ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์ˆ˜๋กœ ์„ ์–ธํ•ด๋„ ์„ ์–ธํ•œ ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

class FixedLengthRange {
	var firstValue: Int 
	let length: Int 

	init(firstValue: Int, length: Int) { 
		self.firstValue = firstValue 
		self.length = length 
	} 
} 

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// ์ƒ์ˆ˜๋กœ ์„ ์–ธ๋œ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋Š” ๋ณ€์ˆ˜๋กœ ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

rangeOfFourItems.firstValue = 5 
// ์˜ค๋ฅ˜ ๋ฐœ์ƒ! rangeOfFourItems.length = 3

 

Lazy Stored Properties

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

 

์–ธ์ œ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋ƒ?

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

class DataImporter {
  /*
  DataImporter ๋Š” ์™ธ๋ถ€ ํŒŒ์ผ์—์„œ ์ž๋ฃŒ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
  ์ด ํด๋ž˜์Šค์˜ ์ดˆ๊ธฐํ™”์—๋Š” ์œ ์˜๋ฏธํ•œ ์–‘์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
  */
  var filename = "data.txt"
  // DataImporter ํด๋ž˜์Šค๋Š” ์—ฌ๊ธฐ์„œ ์ž๋ฃŒ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ๊ฒƒ์ž„
}

class DataManager {
  lazy var importer = DataImporter()
  var data = [String]()
  // DataManager ํด๋ž˜์Šค๋Š” ์—ฌ๊ธฐ์„œ ์ž๋ฃŒ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ๊ฒƒ์ž„
}

let manager = DataManager()
// DataManager์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ฆ.
// ์ฐธ๊ณ ๋กœ, DataManager์˜ ์ €์žฅํ”„๋กœํผํ‹ฐ๋“ค์€ ์ดˆ๊ธฐ๊ฐ’์ด ์žˆ์œผ๋ฏ€๋กœ init์ด ์—†์–ด๋„ ๋จ

manager.data.append("Some data")
manager.data.append("Some more data")
// ํ•˜์ง€๋งŒ ์•„์ง๋„ importer ์†์„ฑ์˜ DataImporter ์ธ์Šคํ„ด์Šค๋Š” ์•„์ง ์ƒ์„ฑํ•˜์ง€ ์•Š์Œ
// -> lazy ์ด๊ธฐ ๋•Œ๋ฌธ

์œ„ ์ฝ”๋“œ์—์„œ importer ๋ผ๋Š” DataImporter ์ธ์Šคํ„ด์Šค๋Š” lazy ์„ ์–ธ์ด ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐ–์—์„œ manage๋ผ๋Š” Datamanager์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•ด importer์— ํ•œ๋ฒˆ๋„ ์ ‘๊ทผ์„ ํ•˜์ง€ ์•Š์•˜๋‹ค. lazy๋กœ ์„ ์–ธํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, importer๊ฐ€ ์ƒ์„ฑ์ด ๋˜์—ˆ๊ฒ ์ง€๋งŒ, lazy๋กœ ์„ ์–ธ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.

 

Stored Properties and Instance Variables

Objective-C ์–ธ์–ด์—์„œ๋Š” ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ์  ์—ฐ์‚ฐ์ž(instance.property = value)๋‚˜ set์—ฐ์‚ฐ์ž(instance.setProperty(value))์œผ๋กœ ๊ฐ’์„ ์ €์žฅํ•œ๋‹ค. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ ๊ด€๋ จํ•œ ๊ฐœ๋…๋„ ํ”„๋กœํผํ‹ฐ์— ํ•จ๊ป˜ ๋ช…์‹œํ•œ๋‹ค. (@property (nonatomic, retain) NSString*propertyName;)

Swift์—์„œ๋Š” ์ด๋Ÿฐ ์ปจ์…‰์„ ํ•˜๋‚˜์˜ ํ”„๋กœํผํ‹ฐ์— ๋…น์—ฌ ์„ ์–ธ๊ณผ ์‚ฌ์šฉ์˜ ํ˜ผ๋ž€์„ ์ค„์˜€๋‹ค. ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฆ„, ํƒ€์ž…, ๋ฉ”๋ชจ๋ฆฌ๊ด€๋ฆฌ ๋“ฑ์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜๋Š” ํ•œ ๊ณณ์—์„œ ์ •์˜ํ•˜๊ฒŒ ๋œ๋‹ค!


 

 

Computed Properties (์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ)

ํด๋ž˜์Šค, ๊ตฌ์กฐ์ฒด, ์—ด๊ฑฐํ˜•์€ ๊ณ„์‚ฐ๋œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์—ฐ์‚ฐํ”„๋กœํผํ‹ฐ๋Š” ์‹ค์ œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, getter๊ณผ optionalํ•œ setter๋ฅผ ์ œ๊ณตํ•ด ๊ฐ’์„ ํƒ์ƒ‰ํ•˜๊ณ  ๊ฐ„์ ‘์ ์œผ๋กœ ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค. 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)
    }
  }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\\(square.origin.x), \\(square.origin.y))")
// "square.origin is now at (10.0, 10.0)" ๋ฅผ ์ธ์‡„ํ•จ

์œ„ ์ฝ”๋“œ๋Š” ์ขŒํ‘œ์™€ํฌ๊ธฐ๋ฅผ ๊ฐ–๋Š” ์‚ฌ๊ฐํ˜•์„ ํ‘œํ˜„ํ•˜๋Š” ๊ตฌ์กฐ์ฒด์— ๊ด€ํ•œ ์ฝ”๋“œ์ด๋‹ค. ์—ฌ๊ธฐ์„œ Rect ๊ตฌ์กฐ์ฒด๋Š” ์‚ฌ๊ฐํ˜•์˜ ์ค‘์ ์„ ํ‘œํ˜„ํ•˜๋Š” center๋ผ๋Š” ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด ํ”„๋กœํผํ‹ฐ๋Š” ๊ณ„์‚ฐ๋œ ํ”„๋กœํผํ‹ฐ์˜ ์ •์˜๋Œ€๋กœ ๊ฐ’์„ ์ง์ ‘ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ์ขŒํ‘œ์™€ ํฌ๊ธฐ ํ”„๋กœํผํ‹ฐ๋“ค์„ ์ ์ ˆํžˆ ์—ฐ์‚ฐํ•ด์„œ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค. (get) ๋˜ set์œผ๋กœ ์‚ฌ๊ฐํ˜•์˜ ์ค‘์ ์„ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๊ฐ’์„ ์„ค์ •ํ•  ๋•Œ x, y ์ขŒํ‘œ๊ฐ€ ์–ด๋–ค ๊ฐ’์„ ๊ฐ€์ ธ์•ผํ•˜๋Š”์ง€ x, y์— ์ ์ ˆํ•œ ์ขŒํ‘œ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค.

โ–ถ ์ฝ”๋“œ์„ค๋ช…

  • ๋‹ค์Œ์œผ๋กœ square.center ์„ ํ†ตํ•ด square ๋ณ€์ˆ˜์˜ center ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•˜๋Š”๋ฐ, ์ด๋Š” center์˜ getter์„ ํ˜ธ์ถœํ•˜์—ฌ ํ˜„์žฌ ์†์„ฑ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค. ๊ธฐ์กด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๊ธฐ ๋ณด๋‹ค๋Š”, ์ƒˆ Point๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค. ์œ„์ฝ”๋“œ์—์„œ ๋ณด๋ฉด, getter๋Š” (5,5)๋ผ๋Š” ์ค‘์‹ฌ์ ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ๊ทธ ๋‹ค์Œ, center ํ”„๋กœํผํ‹ฐ์— (15, 15)๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ์„ค์ •ํ–ˆ๋‹ค. ์ด๋Š” ์ •์‚ฌ๊ฐํ˜•์„ ์˜ค๋ฅธ์ชฝ ์œ„, ์•„๋ž˜ ๊ทธ๋ฆผ์—์„œ๋Š” ์˜ค๋ Œ์ง€์ƒ‰ ์ •์‚ฌ๊ฐํ˜•์˜ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚จ๋‹ค. center ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•˜๋ฉด center์˜ setter์„ ํ˜ธ์ถœํ•˜๋Š”๋ฐ ์ด๋Š” orgin์ด๋ผ๋Š” ์ €์žฅ ํ”„๋กœํผํ‹ฐ์˜ x์™€ y๊ฐ’์„ ์ˆ˜์ •ํ•˜์—ฌ ์ •์‚ฌ๊ฐํ˜•์„ ์ƒˆ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚จ๋‹ค.
  • square ๋ผ๋Š” ์ƒˆ๋กœ์šด Rect ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค. square๋ณ€์ˆ˜๋Š” (0,0) ์ด๋ผ๋Š” ์›์ ๊ณผ, (10, 10)์ด๋ผ๋Š” ํญ๊ณผ ๋†’์ด๋กœ ์ดˆ๊ธฐํ™”๋œ๋‹ค. ์•„๋ž˜ ๊ทธ๋ฆผ์˜ ํŒŒ๋ž€์ƒ‰ ์‚ฌ๊ฐํ˜•์ด ์ด ์‚ฌ๊ฐํ˜•์ด๋‹ค.

์Šค์œ„ํ”„ํŠธ ๊ณต์‹ ๋ฌธ์„œ chap.10 ํ”„๋กœํผํ‹ฐ

Shorted Setter Declaration (Setter ์„ ์–ธ์˜ ๊ฐ„๋žตํ•œ ํ‘œํ˜„)

์•ž์˜ ์ฝ”๋“œ์—์„œ๋Š” Setter์˜ ์ธ์ž ์ด๋ฆ„์„ ์•„๋ž˜์™€ ๊ฐ™์ด set(newCenter)๋ผ๊ณ  ๋ช…์‹œํ–ˆ์ง€๋งŒ, ๋งŒ์•ฝ ์ด๋ ‡๊ฒŒ newCenter๋ผ๊ณ  ์ธ์ž ์ด๋ฆ„์„ ์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์ธ์ž ๊ธฐ๋ณธ ์ด๋ฆ„์ธ newValue๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

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

์œ„ ์ฝ”๋“œ์—์„œ set ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ์ธ์ž ์ด๋ฆ„์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ๋„ newValue.x, newValue.y๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

Shorthand Getter Declaration

์ „์ฒด getter ๋ณธ๋ฌธ์ด ๋‹จ์ผ ํ‘œํ˜„์‹์ด๋ฉด, getter์€ ์•”์‹œ์ ์œผ๋กœ ๊ทธ ํ‘œํ˜„์‹์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

getter์—์„œ return์„ ์ƒ๋žตํ–ˆ๋‹ค. ์ด๋Š” ํ•จ์ˆ˜์—์„œ return์„ ์ƒ๋žตํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๊ทœ์น™์„ ๊ฐ–๋Š”๋‹ค.

 

Read-Only Computed Properties

getter๋งŒ ์žˆ๊ณ  setter๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฝ๊ธฐ์ „์šฉ ํ”„๋กœํผํ‹ฐ๋ผ๊ณ  ํ•œ๋‹ค. ์ฆ‰, ์ฝ๊ธฐ์ „์šฉ ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋Š” ๋ฐ˜๋“œ์‹œ ๋ฐ˜ํ™˜๊ฐ’์„ ์ œ๊ณตํ•˜๊ณ  ๋‹ค๋ฅธ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์—†๋Š” ํ”„๋กœํผํ‹ฐ์ด๋‹ค.

โ–ถ Note

  • ์ฝ๊ธฐ์ „์šฉ ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ํฌํ•จํ•˜์—ฌ ์—ฐ์‚ฐํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ let์ด ์•„๋‹ˆ๋ผ var๋กœ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๋ณดํ†ต ์ฝ๊ธฐ ์ „์šฉ์ด๋ผ ํ•จ์€ ํ•œ๋ฒˆ ๊ฐ’์ด ์ •ํ•ด์ง€๋ฉด ๋ณ€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— let์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ๋งž์œผ๋‚˜, ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋Š” ์ฝ๊ธฐ์ „์šฉ์ด๋ผ ํ•˜๋”๋ผ๋„ ๊ณ„์‚ฐ๊ฐ’์— ๋”ฐ๋ผ ๊ฐ’์ด ๋ณ€ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ผญ var๋กœ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์•ผํ•œ๋‹ค!
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)")
// "the volume of fourByFiveByTwo is 40.0" ๋ฅผ ์ธ์‡„ํ•จ

โ–ถ  ์ฝ”๋“œ์„ค๋ช…

  • width, height, depth ์†์„ฑ์œผ๋กœ 3์ฐจ์› ์ง์‚ฌ๊ฐํ˜• ์†์„ฑ์„ ๋‚˜ํƒ€๋‚ด๋Š” Cuboid ๊ตฌ์กฐ์ฒด
  • ์ด ๊ตฌ์กฐ์ฒด๋Š” ์ง์œก๋ฉด์ฒด์˜ ํ˜„์žฌ ๋ถ€ํ”ผ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋Š” volume์ด๋ผ๋Š” ์ฝ๊ธฐ ์ „์šฉ ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง
  • ํ˜„์žฌ ๊ณ„์‚ฐํ•œ ๋ถ€ํ”ผ๋ฅผ ์™ธ๋ถ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋„๋ก Cuboid ๊ฐ€ ์ฝ๊ธฐ์ „์šฉ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ณตํ•จ

 

Property Observer

ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๋Š” ์ƒˆ ๊ฐ’์ด ์„ค์ •(set)๋  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

  • ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๋Š” ์ƒˆ ๊ฐ’์ด ์ด์ „ ๊ฐ’๊ณผ ๊ฐ™๋”๋ผ๋„ ํ•ญ์ƒ ํ˜ธ์ถœ๋œ๋‹ค.
  • lazy ์ €์žฅ ํ”„๋กœํผํ‹ฐ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค
  • sub class์˜ ํ”„๋กœํผํ‹ฐ์— ์˜ต์ €๋ฒ„๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜๋‹ค
  • ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ์—์„œ๋Š”!! setter ์—์„œ ๊ฐ’์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์˜ต์ €๋ฒ„๋ฅผ ์ •์˜ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

โ–ถ๏ธ willSet

๊ฐ’์ด ์ €์žฅ๋˜๊ธฐ ๋ฐ”๋กœ ์ง์ „์— ํ˜ธ์ถœ ๋จ

willSet์—์„œ๋Š” ์ƒˆ ๊ฐ’์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ช…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ newValue๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

โ–ถ๏ธ didSet

์ƒˆ ๊ฐ’์ด ์ €์žฅ๋˜๊ณ  ๋‚œ ์งํ›„์— ํ˜ธ์ถœ ๋จ

didSet์—์„œ๋Š” ๋ฐ”๋€Œ๊ธฐ ์ „์˜ ๊ฐ’์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด oldValue๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

โ–ถ Note

  • ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐ’์„ ์„ค์ •ํ–ˆ์„ ๋•Œ, ์Šˆํผํด๋ž˜์Šค์˜ initializer๊ฐ€ ํ˜ธ์ถœ ๋œ ํ›„, willSet, didSet ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์Šˆํผํด๋ž˜์Šค์—์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์Šˆํผํด๋ž˜์Šค์˜ initializer๊ฐ€ ํ˜ธ์ถœ๋œ ํ›„ ์˜ต์ €๋ฒ„๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

 

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
// totalSteps ๋ฅผ 200 ์œผ๋กœ ์„ค์ •ํ•˜๋ ค๊ณ  ํ•จ
//200 ๊ฑธ์Œ์„ ์ถ”๊ฐ€ํ•จ

stepCounter.totalSteps= 360
// totalSteps ๋ฅผ 360 ์œผ๋กœ ์„ค์ •ํ•˜๋ ค๊ณ  ํ•จ
// 160 ๊ฑธ์Œ์„ ์ถ”๊ฐ€ํ•จ

stepCounter.totalSteps= 896
// totalSteps ๋ฅผ 896 ์œผ๋กœ ์„ค์ •ํ•˜๋ ค๊ณ  ํ•จ
// 536 ๊ฑธ์Œ์„ ์ถ”๊ฐ€ํ•จ

ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„ willSet๊ณผ didSet์„ ์‚ฌ์šฉํ–ˆ๋‹ค. willSet์—์„œ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์œผ๋กœ newTotalSteps๋ฅผ ์ง€์ •ํ•ด์„œ ์‚ฌ์šฉํ–ˆ๊ณ , didSet์—์„œ๋Š” ๋ณ€ํ•˜๊ธฐ ์ „์˜ ๊ฐ’์„ ์˜๋ฏธํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์„ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  oldValue๋ผ๋Š” ๊ธฐ๋ณธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์„ ์ด์šฉํ–ˆ๋‹ค.

โ–ถ ์ฝ”๋“œ ์„ค๋ช…

  • willSet์€ ์ƒˆ๋กœ ๋‹ค๊ฐ€์˜ฌ ๊ฐ’์œผ๋กœ, newTotalSteps ๋ผ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ–ˆ๊ณ  ์ด ์˜ˆ์ œ์—์„œ๋Š” ์„ค์ •ํ•˜๋ ค๋Š” ๊ฐ’์„ ๋‹จ์ˆœํžˆ ์ธ์‡„ํ•ด์ค€๋‹ค.
  • totalStep๊ฐ’์„ ๊ฐฑ์‹  ํ•œ ํ›„, didSet์ด ํ˜ธ์ถœ๋จ. totalSteps ๊ฐ’๊ณผ ์˜ˆ์ „ ๊ฐ’์„ ๋น„๊ตํ•ด์„œ ์ด ๊ฑธ์Œ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ–ˆ์œผ๋ฉด, ์ƒˆ ๊ฑธ์Œ ์ˆ˜๊ฐ€ ์–ผ๋งˆ์ธ์ง€ ํ‘œ์‹œํ•˜๊ณ ์ž ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•จ.
  • didSet์€ ์˜ˆ์ „ ๊ฐ’์— ์‚ฌ์šฉ์ž ์ •์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ  oldValue๋ผ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•จ.

 

Property Wrappers

Property Wrapper ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ €์žฅ๋˜๋Š” ๋ฐฉ์‹์„ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•˜๋Š” ์ฝ”๋“œ ์‚ฌ์ด์— ๋ถ„๋ฆฌ ๊ณ„์ธต์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์–ธ์ œ ์‚ฌ์šฉํ•˜๋ƒ?

  • Thread-safeํ•œ ํ”„๋กœํผํ‹ฐ ๋˜๋Š” ๊ฐ’์„ DB์— ์ €์žฅํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ํ•„์š”ํ•  ๋•Œ
    • ์ง€๊ธˆ๊นŒ์ง€๋Š” ์ด๋Ÿด ๋•Œ thread-safe ์ฒ˜๋ฆฌ, DB ์ปค๋„ฅ์…˜ ์ฒ˜๋ฆฌ ๋“ฑ์„ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ๊ฐ๊ฐ์˜ ํ”„๋กœํผํ‹ฐ์— ๋ชจ๋‘ ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผ ํ–ˆ์Œ.
    • Property wrapper ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ์ด๋Ÿฐ ์ฝ”๋“œ (๊ฐ’ ์ €์žฅ์„ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ)๋“ค์„ Property wrapper๋ฅผ ์ •์˜ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ์ตœ์ดˆ ํ•œ ๋ฒˆ๋งŒ ์ž‘์„ฑํ•˜๋ฉด ๋จ.
    • ๊ทธ ํ›„ ํ•„์š”ํ•œ ํ”„๋กœํผํ‹ฐ๋“ค์—์„œ ์ด wrapper๋ฅผ ๊ฐ€์ ธ๋‹ค ์ ์šฉํ•จ์œผ๋กœ์จ ํ•˜๋‚˜์˜ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ.

Property wrapper ์‚ฌ์šฉ์„ ์œ„ํ•ด์„œ๋Š” ๊ตฌ์กฐ์ฒด, ํด๋ž˜์Šค, ์—ด๊ฑฐํ˜•์—์„œ wrapperValue๋ผ๊ณ  ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•ด์•ผํ•œ๋‹ค. ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

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

์œ„ ์ฝ”๋“œ์—์„œ๋Š” TwelveOrLess ๊ตฌ์กฐ์ฒด๋Š” wrappedValue์— ํ•ญ์ƒ 12๋ณด๋‹ค ์ž‘์€ ๊ฐ’์ด ์ €์žฅ๋˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ฝ”๋“œ์ด๋‹ค. ๋งŒ์•ฝ 12๋ณด๋‹ค ํฐ ์ˆ˜๋ผ๋ฉด, 12๋ฅผ ์ €์žฅํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. ์œ„์—์„œ ์„ ์–ธํ•œ TwelveOrLess ๊ตฌ์กฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

struct SmallRectangle {
  @TwelveOrLess var height: Int
  @TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()
print(rectangle.height)
// "0" ์„ ์ธ์‡„ํ•จ

rectangle.height = 10
print(rectangle.height)
// "10" ์„ ์ธ์‡„ํ•จ

rectangle.height = 24
print(rectangle.height)
// "12" ๋ฅผ ์ธ์‡„ํ•จ

์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ์— Property wrapper๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Property wrapper๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Property Wrapper์˜ ์ด๋ฆ„์„ @๋ฅผ ํ•จ๊ป˜ ์จ์ฃผ๋ฉด ๋œ๋‹ค. SmallRectangle์˜ height, width ํ”„๋กœํผํ‹ฐ๋Š” Property wrapper ๊ฐ€ ์ ์šฉ๋œ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— 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 }
  }
}

์œ„์™€ Property Wrapper๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด property wrapper๋กœ ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ์— ๊ฐ’์„ ์ €์žฅํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— getter, setter๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

Setting Initial Values for Wrapped Properties

์œ„์— ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋Š” property wrapper์—์„œ ์ดˆ๊ธฐ๊ฐ’์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ๋•Œ๋ฌธ์— ๋ž˜ํ•‘๋œ ํ”„๋กœํผํ‹ฐ๋Š” ๋‹ค๋ฅธ ์ดˆ๊ธฐ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์—†์—ˆ๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” property wrapper์— ์ƒ์„ฑ์ž๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

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

์œ„์˜ ์ฝ”๋“œ์—์„œ property wrapper๋กœ ์‚ฌ์šฉ๋  ๊ตฌ์กฐ์ฒด์—๋Š” 3๊ฐœ์˜ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ์ž๊ฐ€ ์ถ”๊ฐ€๋œ property wrapper๋ฅผ ์ ์šฉํ•œ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด์ž.

 

struct ZeroRectangle {
  @SmallNumber var height: Int
  @SmallNumber var width: Int
}

var zeroRectangle = ZeroRectangle()
print(zeroRectangle.height, zeroRectangle.width)
// "0 0" ๋ฅผ ์ธ์‡„ํ•จ

์ด์   ์ƒ์ •์ž๋ฅผ ํ†ตํ•ด์„œ ์ดˆ๊ธฐ ๊ฐ’์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

var unitRectangle = UnitRectangle()
print(unitRectangle.height, unitRectangle.width)
// "1 1" ๋ฅผ ์ธ์‡„ํ•จ

์œ„์™€ ๊ฐ™์ด height, width์— 1์„ ํ• ๋‹นํ•˜๊ฒŒ ๋˜๋ฉด ์ด๋Š” property wrapper์˜ init ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค.

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)
// "2 3" ๋ฅผ ์ธ์‡„ํ•จ

narrowRectangle.height = 100
narrowRectangle.width = 100
print(narrowRectangle.height, narrowRectangle.width)
// "5 4" ๋ฅผ ์ธ์‡„ํ•จ

property wrapper์˜ ์ธ์ˆ˜๋ฅผ ํฌํ•จํ•  ๋•Œ ํ• ๋‹น์„ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. heightํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ์‹ธ๋Š” SmallNumber ์ธ์Šคํ„ด์Šค๋Š” SmallNumber(wrappedValue:1)์„ ํ˜ธ์ถœํ•˜์—ฌ ์ดˆ๊ธฐํ™” ํ–ˆ๊ณ , width ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ์‹ธ๋Š” SmallNumber ์ธ์Šคํ„ด์Šค๋Š” SmallNumber(wrappedValue:2, maximum:9)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ดˆ๊ธฐํ™”๋œ๋‹ค.


 

Global and Local Variables

์•ž์—์„œ ์†Œ๊ฐœํ•œ ๊ณ„์‚ฐ๋œ ํ”„๋กœํผํ‹ฐ์™€ ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„ ๊ธฐ๋Šฅ์€ ์ „์—ญ๋ณ€์ˆ˜์™€ ์ง€์—ญ๋ณ€์ˆ˜ ๋ชจ๋‘์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ „์—ญ๋ณ€์ˆ˜(global)๋Š” ์–ด๋–ค ํ•จ์ˆ˜๋‚˜, ๋ฉ”์†Œ๋“œ, ํด๋กœ์ € ๋ฐ ํƒ€์ž… ๋ฐ–์—์„œ ์ •์˜ํ•œ ๋ณ€์ˆ˜์ด๋‹ค. ์ง€์—ญ๋ณ€์ˆ˜(local)์€ ํ•จ์ˆ˜๋‚˜, ๋ฉ”์†Œ๋“œ ๋ฐ ํด๋กœ์ € ์•ˆ์—์„œ ์ •์˜ํ•œ ๋ณ€์ˆ˜์ด๋‹ค.

์•ž์„œ ๋ฐฐ์šด ๋ชจ๋“  ์ „์—ญ๋ณ€์ˆ˜์™€ ์ง€์—ญ๋ณ€์ˆ˜๋Š” Stored Variable (์ €์žฅ๋œ ๋ณ€์ˆ˜) ์˜€๋‹ค. ์ด๋Š” ์ €์žฅ ํ”„๋กœํผํ‹ฐ์™€ ๋น„์Šทํ•˜๊ฒŒ ๊ฐ’์—๊ฒŒ ์ €์žฅ๊ณต๊ฐ„์„ ์ฃผ๊ณ  ํ•ด๋‹น ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ , ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

๋ฌผ๋ก , ์ „์—ญ ๋ฒ”์œ„์™€ ์ง€์—ญ ๋ฒ”์œ„์—์„œ Computed Variable๋ฅผ ์ •์˜ํ•˜๊ณ  ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์˜ต์ €๋ฒ„๋ฅผ ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. Computed Variable์€ ๊ฐ’์„ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ๊ณ„์‚ฐ ํ”„๋กœํผํ‹ฐ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์“ฐ์ธ๋‹ค.

์ „์—ญ๋ณ€์ˆ˜, ์ƒ์ˆ˜๋Š” lazy ์ €์žฅ ํ”„๋กœํผํ‹ฐ์™€ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ „์—ญ๋ณ€์ˆ˜ ๋ฐ ์ƒ์ˆ˜์— lazyํ‚ค์›Œ๋“œ๋ฅผ ํ‘œ์‹œํ•  ํ•„์š”๋Š” ์—†๋‹ค.

์ด์™€ ๋ฐ˜๋Œ€๋กœ ์ง€์—ญ๋ณ€์ˆ˜, ์ƒ์ˆ˜์—๋Š” ์ ˆ๋Œ€๋กœ lazy๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.


 

Type Properties

๊ฐ๊ฐ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹Œ ํƒ€์ž… ์ž์ฒด์— ์†ํ•˜๊ฒŒ ๋˜๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋ผ๊ณ  ํ•œ๋‹ค.

์ด์ œ๊นŒ์ง€ ์•Œ์•„๋ณธ ํ”„๋กœํผํ‹ฐ ๊ฐœ๋…์€ ๋ชจ๋‘ ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  ๊ทธ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์„๋•Œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ์ด๋‹ค. ์ธ์Šคํ„ด์Šค ํ”„๋กœํผํ‹ฐ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•  ๋•Œ ๋งˆ๋‹ค ์ดˆ๊นƒ๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์ด ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์ด ๋˜๊ณ , ๊ฐ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฐ’์„ ์ง€๋‹ ์ˆ˜ ์žˆ๋‹ค.

ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋Š” ํƒ€์ž… ์ž์ฒด์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ํ”„๋กœํผํ‹ฐ์ด๊ณ  ์ธ์Šคํ„ด์Šค์˜ ์ƒ์„ฑ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด ํƒ€์ž… ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์€ ํ•˜๋‚˜์ด๋‹ค. ์ด ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋Š” ํŠน์ • ํƒ€์ž…์˜ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค์— ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’์„ ์ •์˜ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

 

Type Property Syntax

ํƒ€์ž…์†์„ฑ์€ static ํ‚ค์›Œ๋“œ๋กœ ์ •์˜ํ•œ๋‹ค. ํด๋ž˜์Šค์—์„œ๋Š” static๊ณผ class ์ด๋ ‡๊ฒŒ 2๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๋‘๊ฐ€์ง€ ๊ฒฝ์šฐ์˜ ์ฐจ์ด๋Š” ์„œ๋ธŒํด๋ž˜์Šค์—์„œ overriding ๊ฐ€๋Šฅ ์—ฌ๋ถ€์ด๋‹ค. class ๋กœ ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ๋Š” ์„œ๋ธŒํด๋ž˜์Šค์—์„œ override ๊ฐ€๋Šฅํ•˜๋‹ค.

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

  • ์œ„์˜ ์—ฐ์‚ฐ ํƒ€์ž… ํ”„๋กœํผํ‹ฐ ์˜ˆ์‹œ๋Š” ์ฝ๊ธฐ์ „์šฉ์ด์ง€๋งŒ, ๊ฐ™์€ ๋ฌธ๋ฒ•์œผ๋กœ ์—ฐ์‚ฐ๋œ ์ธ์Šคํ„ด์Šค์˜ ํƒ€์ž… ํ”„๋กœํผํ‹ฐ์—์„œ๋Š” ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๋Š” ํ”„๋กœํผํ‹ฐ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค. (์•„๋ž˜์˜ˆ์‹œ)
class Aclass {
    // ์ €์žฅ ํƒ€์ž… ํ”„๋กœํผํ‹ฐ
    static var typeProperty: Int = 0
    
    var instanceProperty: Int = 0 {
        didSet {
            Aclass.typeProperty = instanceProperty + 100
        }
    }
    
    // ์—ฐ์‚ฐ ํƒ€์ž… ํ”„๋กœํผํ‹ฐ
    static var typeComputedProperty: Int {
        get {
            return typeProperty
        }
        
        set {
            typeProperty = newValue
        }
    }
}
  • ์ถ”๊ฐ€์„ค๋ช…
    • ์ €์žฅ&์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ ์•ž์— static ์ด๋ž€ ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ์ €์žฅ(์—ฐ์‚ฐ)ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋จ

 

Querying and Setting Type Properties

ํƒ€์ž… ํ”„๋กœํผํ‹ฐ๋Š” ๊ทธ๋ƒฅ ์ธ์Šคํ„ด์Šค ์†์„ฑ๊ณผ ๊ฐ™์ด ์  ๊ตฌ๋ฌธ์œผ๋กœ ์กฐํšŒํ•˜๊ณ  ์„ค์ •ํ•œ๋‹ค.

print(SomeStructure.storedTypeProperty)
// "Some value." ๋ฅผ ์ธ์‡„ํ•จ
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// "Another value." ๋ฅผ ์ธ์‡„ํ•จ
print(SomeEnumeration.computedTypeProperty)
// "6" ์„ ์ธ์‡„ํ•จ
print(SomeClass.computedTypeProperty)
// "27" ์„ ์ธ์‡„ํ•จ

์•„๋ž˜ ์˜ค๋””์˜ค ์ฑ„๋„์˜ ๋ณผ๋ฅจ์„ ์กฐ์ ˆํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ์ฒด ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž.

์Šค์œ„ํ”„ํŠธ ๊ณต์‹๋ฌธ์„œ chap10. ํ”„๋กœํผํ‹ฐ

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

์œ„ ์ฝ”๋“œ๋Š” ํ˜„์žฌ ์˜ค๋””์˜ค ์ตœ๋Œ€ ๋ณผ๋ฅจ ํฌ๊ธฐ๋Š” ํƒ€์ž…ํ”„๋กœํผํ‹ฐ maxInputLevelForAllChannels๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ๊ทธ ๊ฐ’์€ thresholdLevel๋กœ ์ƒ์ˆ˜๋กœ ์ •์˜๋ผ ์žˆ์–ด์„œ currentLevel์„ ์„ค์ •ํ• ๋•Œ ๋งˆ๋‹ค (didSet) ์ฑ„๋„๋ณ„ ๋ณผ๋ฅจ์ด ์ตœ๋Œ€ ๊ทธ ๊ฐ’์„ ๋„˜์ง€ ๋ชปํ•˜๋„๋ก ์กฐ์ •ํ•ด์ฃผ๋Š” ๊ตฌ์กฐ์ฒด์ด๋‹ค.

 

์ด๋ ‡๊ฒŒ ๋งŒ๋“  ์˜ค๋””์˜ค ์ฒด๋„ ๊ตฌ์กฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์ขŒ์šฐ ๋‘๊ฐœ์˜ ์˜ค๋””์˜ค ์ฑ„ํ„ธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

์ด์ œ leftChannel์— 7์„ ํ• ๋‹นํ•ด๋ณด์ž.

leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// Prints "7"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "7"

๊ทธ๋Ÿผ ์ฑ„๋„์—์„œ ์ตœ๋Œ€๊ฐ’์œผ๋กœ ์„ค์ •ํ•œ ๊ฐ’์„ ๋„˜์–ด๊ฐ€๋Š” 11์„ ํ• ๋‹นํ•ด๋ณด์ž.

rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// Prints "10"
print(AudioChannel.maxInputLevelForAllChannels)
// Prints "10"

์ตœ๋Œ€๊ฐ’ 10์ด ๋„˜์–ด๊ฐ€๋Š” ๊ฐ’์„ ํ• ๋‹นํ•˜์ž, 11์„ ์ž…๋ ฅํ–ˆ์ง€๋งŒ 10์œผ๋กœ ์„ค์ •๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜์‘ํ˜•