iOS/Swift

[Swift] Property(ν”„λ‘œνΌν‹°)에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μž.

κ²½ν‘Έ 2023. 4. 8. 13:30
λ°˜μ‘ν˜•

μ•ˆλ…•ν•˜μ„Έμš”~

 

μ˜€λŠ˜μ€ Swiftμ—μ„œ μ‚¬μš©ν•˜λŠ” ν”„λ‘œνΌν‹°μ— λŒ€ν•΄μ„œ μ •λ¦¬ν•˜λ €κ³  ν•©λ‹ˆλ‹€ : )

 

 


 

ν”„λ‘œνΌν‹°λž€

클래슀, ꡬ쑰체, μ—΄κ±°ν˜• λ“±μ˜ 데이터 νƒ€μž… 내에 μ„ μ–Έλ˜μ–΄ μžˆλŠ” λ³€μˆ˜ λ˜λŠ” μƒμˆ˜λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€. ν”„λ‘œνΌν‹°λŠ” ν•΄λ‹Ή 데이터 νƒ€μž… λ‚΄μ—μ„œ 데이터λ₯Ό μ €μž₯ν•˜κ±°λ‚˜, κ³„μ‚°ν•˜λŠ” λ“±μ˜ 역할을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

ν”„λ‘œνΌν‹°λŠ” 기본적으둜 μ €μž₯ ν”„λ‘œνΌν‹°μ™€ κ³„μ‚°λœ ν”„λ‘œνΌν‹°λ‘œ λ‚˜λˆŒ 수 μžˆμŠ΅λ‹ˆλ‹€.

μ €μž₯ ν”„λ‘œνΌν‹°λŠ” 값을 μ €μž₯ν•˜κ³ , κ³„μ‚°λœ ν”„λ‘œνΌν‹°λŠ” 값을 κ³„μ‚°ν•˜μ—¬ λ°˜ν™˜ν•©λ‹ˆλ‹€.

λ˜ν•œ, ν”„λ‘œνΌν‹°μ— μ ‘κ·Όν•˜κ±°λ‚˜ 값이 변경될 λ•Œ μ‹€ν–‰λ˜λŠ” μ½”λ“œλ₯Ό μΆ”κ°€ν•  수 μžˆλŠ” ν”„λ‘œνΌν‹° μ˜΅μ €λ²„λ„ μ œκ³΅λ©λ‹ˆλ‹€.

 

Swiftμ—μ„œλŠ” ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•  λ•Œ var ν‚€μ›Œλ“œλ‘œ λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜κ±°λ‚˜, let ν‚€μ›Œλ“œλ‘œ μƒμˆ˜λ₯Ό μ„ μ–Έν•©λ‹ˆλ‹€.

ν”„λ‘œνΌν‹°λŠ” ν•΄λ‹Ή 데이터 νƒ€μž… λ‚΄μ—μ„œ μ„ μ–Έλ˜μ–΄ μžˆμœΌλ―€λ‘œ, μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ ν”„λ‘œνΌν‹°λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ±°λ‚˜, 값에 μ ‘κ·Όν•  λ•Œ ν•΄λ‹Ή 데이터 νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 톡해 μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 ν”„λ‘œνΌν‹°μ˜ μ’…λ₯˜

1. μ €μž₯ ν”„λ‘œνΌν‹° (Stored Properties)

μ €μž₯ ν”„λ‘œνΌν‹°λŠ” κ°€μž₯ κ°„λ‹¨ν•œ ν˜•νƒœμ˜ ν”„λ‘œνΌν‹°λ‘œ, 값을 μ €μž₯ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. 클래슀, ꡬ쑰체, μ—΄κ±°ν˜• λ“±μ—μ„œ μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ €μž₯ ν”„λ‘œνΌν‹°λŠ” var λ˜λŠ” let ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€. var둜 μ„ μ–Έν•œ μ €μž₯ ν”„λ‘œνΌν‹°λŠ” 값을 λ³€κ²½ν•  수 μžˆμ§€λ§Œ, let으둜 μ„ μ–Έν•œ μ €μž₯ ν”„λ‘œνΌν‹°λŠ” 값을 λ³€κ²½ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

struct Person {
    var name: String
    let age: Int
}

var person = Person(name: "κ²½ν‘Έ", age: 20)
person.name = "경호" // name ν”„λ‘œνΌν‹°λ₯Ό λ³€κ²½ν•  수 있음
person.age = 31 // age ν”„λ‘œνΌν‹°λ₯Ό λ³€κ²½ν•  수 μ—†μŒ (였λ₯˜ λ°œμƒ)

 Person ꡬ쑰체에 nameκ³Ό ageλΌλŠ” μ €μž₯ ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•œ 이후 Person μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³ , μƒμ„±λœ μΈμŠ€ν„΄μŠ€μ˜ name ν”„λ‘œνΌν‹°λ₯Ό λ³€κ²½ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ•žμ„œ μ„€λͺ…ν•œ 것과 같이 age ν”„λ‘œνΌν‹°λŠ” let으둜 μ„ μ–Έλ˜μ–΄ μžˆμœΌλ―€λ‘œ 값을 λ³€κ²½ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

 

2. μ—°μ‚° ν”„λ‘œνΌν‹° (Computed Properties)

μ—°μ‚° ν”„λ‘œνΌν‹°λŠ” μ €μž₯된 값을 가지지 μ•ŠμœΌλ©°, getter와 setterλ₯Ό μ‚¬μš©ν•˜μ—¬ 값을 κ³„μ‚°ν•©λ‹ˆλ‹€. getterλŠ” ν”„λ‘œνΌν‹° 값을 λ°˜ν™˜ν•˜κ³ , setterλŠ” μƒˆ 값을 μ„€μ •ν•©λ‹ˆλ‹€. μ—°μ‚° ν”„λ‘œνΌν‹°λŠ” var ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•˜λ©°, getκ³Ό set 블둝을 μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•©λ‹ˆλ‹€.

struct Rectangle {
    var width = 0.0
    var height = 0.0
    
    var area: Double {
        get {
            return width * height
        }
        set(newArea) {
            height = newArea / width
        }
    }
}

var rect = Rectangle(width: 10.0, height: 5.0)
print(rect.area) // 50.0

rect.area = 100.0
print(rect.height) // 10.0

Rectangle ꡬ쑰체에 width, height, areaλΌλŠ” ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•˜κ³  area ν”„λ‘œνΌν‹°λŠ” μ—°μ‚° ν”„λ‘œνΌν‹°λ‘œ, λ„ˆλΉ„μ™€ 높이λ₯Ό κ³±ν•œ 값을 λ°˜ν™˜ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ area ν”„λ‘œνΌν‹°μ˜ setterλ₯Ό μ‚¬μš©ν•˜μ—¬ 높이 값을 κ³„μ‚°ν•˜λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 이후 Rectangle μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³ , area ν”„λ‘œνΌν‹°λ₯Ό 좜λ ₯ν•œ ν›„, area 값을 λ³€κ²½ν•˜κ²Œ 되면 height 값을 λ‹€μ‹œ κ³„μ‚°ν•˜κ³  μžˆλŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

3. 지연 μ €μž₯ ν”„λ‘œνΌν‹° (Lazy Stored Properties)

지연 μ €μž₯ ν”„λ‘œνΌν‹°λŠ” ν•΄λ‹Ή ν”„λ‘œνΌν‹°κ°€ 처음으둜 호좜될 λ•Œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€. 일반적으둜 μ΄ˆκΈ°ν™” λΉ„μš©μ΄ 많이 λ“œλŠ” κ°μ²΄λ‚˜ 파일 μž…μΆœλ ₯ λ“±μ˜ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” ν”„λ‘œνΌν‹°μ— μ‚¬μš©λ©λ‹ˆλ‹€. 지연 μ €μž₯ ν”„λ‘œνΌν‹°λŠ” var ν‚€μ›Œλ“œμ™€ ν•¨κ»˜ lazy ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•©λ‹ˆλ‹€.

struct Book {
    let title: String
    let author: String
    lazy var contents: String = {
        guard let fileUrl = Bundle.main.url(forResource: "bookContents", withExtension: "txt"),
              let contents = try? String(contentsOf: fileUrl)
        else {
            return "컨텐츠λ₯Ό λΆˆλŸ¬μ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€."
        }
        return contents
    }()
}

 

Book κ΅¬μ‘°μ²΄λŠ” νŒŒμΌμ—μ„œ μ±… λ‚΄μš©μ„ μ½μ–΄μ™€μ„œ contents ν”„λ‘œνΌν‹°μ— μ €μž₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ, νŒŒμΌμ—μ„œ 데이터λ₯Ό μ½μ–΄μ˜€λŠ” μž‘μ—…μ€ λΉ„μš©μ΄ 많이 λ“œλŠ” μž‘μ—…μ΄κΈ° λ•Œλ¬Έμ— μ΄ˆκΈ°ν™” μ‹œμ μ— ν•˜κ²Œ 되면 μ•± μ‹€ν–‰ 속도가 느렀질 μš°λ €κ°€ μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œ 지연 μ €μž₯ ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•΄λ‹Ή ν”„λ‘œνΌν‹°κ°€ 처음 접근될 λ•Œμ—λ§Œ νŒŒμΌμ—μ„œ 데이터λ₯Ό μ½μ–΄μ˜€λ„λ‘ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

 

4. ν”„λ‘œνΌν‹° μ˜΅μ €λ²„ (Property Observers)

ν”„λ‘œνΌν‹° μ˜΅μ €λ²„λŠ” μ €μž₯ ν”„λ‘œνΌν‹°μ˜ 값이 변경될 λ•Œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œμž…λ‹ˆλ‹€. ν”„λ‘œνΌν‹° μ˜΅μ €λ²„λŠ” willSetκ³Ό didSet 블둝을 μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•©λ‹ˆλ‹€. willSet 블둝은 μƒˆλ‘œμš΄ 값이 μ €μž₯되기 전에 호좜되며, didSet 블둝은 μƒˆλ‘œμš΄ 값이 μ €μž₯된 후에 ν˜ΈμΆœλ©λ‹ˆλ‹€.

class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("μŠ€ν…μ€ 총 :\(newTotalSteps), ", terminator: "")
        }
        didSet {
            if totalSteps > oldValue {
                print("μΆ”κ°€ν•œ μŠ€ν…μˆ˜ : \(totalSteps - oldValue) steps")
            }
        }
    }
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 10 // μŠ€ν…μ€ 총 :10, μΆ”κ°€ν•œ μŠ€ν…μˆ˜ : 10 steps
stepCounter.totalSteps = 20 // μŠ€ν…μ€ 총 :20, μΆ”κ°€ν•œ μŠ€ν…μˆ˜ : 10 steps

μœ„μ˜ μ˜ˆμ œμ—μ„œλŠ” StepCounter ν΄λž˜μŠ€μ— totalStepsλΌλŠ” μ €μž₯ ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•˜μ˜€μŠ΅λ‹ˆλ‹€. totalSteps ν”„λ‘œνΌν‹°μ— willSetκ³Ό didSet 블둝을 μΆ”κ°€ν•˜μ—¬, 값이 변경될 λ•Œλ§ˆλ‹€ λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.

 

5. νƒ€μž… ν”„λ‘œνΌν‹° (Type Properties)

νƒ€μž… ν”„λ‘œνΌν‹°λŠ” ν΄λž˜μŠ€λ‚˜ ꡬ쑰체 μžμ²΄μ— μ†ν•˜λŠ” ν”„λ‘œνΌν‹°λ‘œ, ν•΄λ‹Ή νƒ€μž…μ˜ λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°€ κ³΅μœ ν•˜λŠ” κ°’μž…λ‹ˆλ‹€. νƒ€μž… ν”„λ‘œνΌν‹°λŠ” static ν‚€μ›Œλ“œλ‚˜ class ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„ μ–Έν•©λ‹ˆλ‹€. static ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 상속이 λΆˆκ°€λŠ₯ν•œ νƒ€μž… ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€. 반면, class ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 상속이 κ°€λŠ₯ν•œ νƒ€μž… ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

class SomeClass {
    static var someTypeProperty = "Some Value"
}

struct SomeStruct {
    static var someTypeProperty = "Some Value"
}

enum SomeEnum {
    static var someTypeProperty = "Some Value"
}

print(SomeClass.someTypeProperty) // Some Value
print(SomeStruct.someTypeProperty) // Some Value
print(SomeEnum.someTypeProperty) // Some Value

μœ„μ˜ μ˜ˆμ œμ—μ„œλŠ” SomeClass, SomeStruct, SomeEnum에 각각 someTypePropertyλΌλŠ” νƒ€μž… ν”„λ‘œνΌν‹°λ₯Ό μ„ μ–Έν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. νƒ€μž… ν”„λ‘œνΌν‹°λŠ” ν•΄λ‹Ή νƒ€μž…μ˜ λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°€ κ³΅μœ ν•˜κΈ° λ•Œλ¬Έμ—, κ°’μ˜ 변경이 λͺ¨λ“  μΈμŠ€ν„΄μŠ€μ— 영ν–₯을 λ―ΈμΉ©λ‹ˆλ‹€. 

SomeClass.someTypeProperty = "New Value"
print(SomeClass.someTypeProperty) // New Value

 

즉, μœ„μ™€ 같이 SomeClass의 someTypeProperty 값을 λ³€κ²½ν•˜κ³  λ‚˜μ„œ SomeClass.someTypePropertyλ₯Ό 좜λ ₯ν•˜λ©΄, μƒˆλ‘œμš΄ 값인 "New Value"κ°€ 좜λ ₯λ©λ‹ˆλ‹€.

 

 

 

λ°˜μ‘ν˜•