swift 프로퍼티 정리 2

swift 프로퍼티 정리 2

 

✅프로퍼티 감시자

프로퍼티 감시자를 사용하면 프로퍼티의 값이 변경됨에 따라 적절한 작업을 수행할 수 있습니다

 

프로퍼티 감시자는 프로퍼티의 값이 새로 할당될 때마다 호출합니다.

 

프로퍼티 감시자는 저장 프로퍼티 뿐만 아니라 프로퍼티를 재정의해 상속받은 저장 프로퍼티 또는 연산 프로퍼티에도 적용가능합니다.

 

상속 받지 않은 연산 프로퍼티에는 프로퍼티 감시자를 사용할 필요가 없으며 할 수도 없습니다.

 

연산 프로퍼티의 접근자(get)와 설정자(set)를 통해서 프로퍼티 감시자를 구현할 수 있기 때문입니다.

 

연산 프로퍼티는 상속받았을 때만 프로퍼티 재정의를 통해서 프로퍼티 감시자를 사용합니다.


프로퍼티 감시자 종류

willSet - 프로퍼티 값이 변경되기 전에 호출
didSet - 프로퍼티 값이 변경되고나서 호출

class Account{
    
    //저장 프로퍼티
    var credit:Int = 0{
        //프로퍼티 감시자
        willSet{
            print("[Account] 잔액이 \(credit)원에서 \(newValue)원으로 변경될 예정입니다.")
        }
        
        didSet{
            print("[Account] 잔액이 \(oldValue)원에서 \(credit)원으로 변경되었습니다.")
        }
    }
    
    //연산 프로퍼티
    var dollarValue:Double {
        get{
            return Double(credit)
        }
        
        set{
            credit = Int(newValue * 1000)
            print("[Account] 잔액을 \(newValue) 달러로 변경 중 입니다.")
        }
    }
}

let myAccount:Account = Account()
//잔액이 0원에서 1000원으로 변경될 예정입니다.
myAccount.credit = 1000
//잔액이 0원에서 1000원으로 변경되었습니다.

 

클래스를 상속받았다면 기존의 연산 프로퍼티를 재정의하여 프로퍼티 감시자를 구현할 수도 있습니다.

연산 프로퍼티를 재정의해도 기존의 연산 프로퍼티 기능(접근자 get 와 설정자 set)은 동작 합니다.
 

아래 코드는 연산 프로퍼티인 dollarValue가 포함되어 있는 Account 클래스를 상속 받은 ForeinAccount 클래스에서

기존 dollarValue 프로퍼티를 재정의하여 프로퍼티 감시자를 구현하는 예제입니다.

 

class ForeignAccount:Account {
    
    override var dollarValue: Double{
        //프로퍼티 감시자
        willSet{
            print("[override - dollarValue] 잔액이 \(dollarValue)에서 \(newValue)로 변경될 예정입니다.")
        }
        
        didSet{
            print("[override - dollarValue] 잔액이 \(oldValue)달러에서 \(dollarValue) 달러로 변경되었습니다.")
        }
    }
}

let foreignAccount:ForeignAccount = ForeignAccount()

//잔액이 0원에서 1000원으로 변경될 예정입니다.
foreignAccount.credit = 1000
//잔액이 0원에서 1000원으로 변경되었습니다.

print("")


//[override - dollarValue] 잔액이 1000.0에서 2.0로 변경될 예정입니다.
//[Account] 잔액이 1000원에서 2000원으로 변경될 예정입니다.
//[Account] 잔액이 1000원에서 2000원으로 변경되었습니다.

foreignAccount.dollarValue = 2      //[Account] 잔액을 2.0 달러로 변경 중 입니다.


//[override - dollarValue] 잔액이 1000.0달러에서 2000.0 달러로 변경되었습니다.

 

 

전역 변수와 지역변수

연산 프로퍼티와 프로퍼티 감시자는 전역변수와 지역변수 모두에 사용할 수 있습니다.

 

따라서 프로퍼티에 한정하지 않고, 전역에서 쓰일 수 있는 변수와 상수에도 두 기능을 사용할 수 있습니다.
 

위에서 변수라고 통칭했던 전역 변수 또는 지역 변수는 저장변수라고 할 수 있습니다.
 

저장변수는 마치 저장 프로퍼티처럼 값을 저장하는 역할을 합니다.
 

그런데 전역변수나 지역변수를 연산변수로 구현할 수도 있으며, 프로퍼티 감시자를 구현할 수도 있습니다.
 

참고로 전역변수 또는 전역상수는 지연 저장 프로퍼티 처럼 처음 접근할 때 최초로 연산이 이루어 집니다.
 

lazy 키워드를 사용하여 연산을 늦출 필요가 없습니다.
 

반대로 지역 변수 및 지역 상수는 절대로 지연 연산되지 않습니다.
 

아래는 저장 변수에 감시자를 구현했고, 연산 변수를 구현 했습니다.

 

//저장 프로퍼티
var wonInPocket:Int = 2000{
    //프로퍼티 감시자
    willSet{
        print("주머니의 돈이 \(wonInPocket)에서 \(newValue)원으로 변경될 예정입니다.")
    }
    didSet{
        print("주머니의 돈이 \(oldValue)에서 \(wonInPocket)원으로 변경되었습니다.")
    }
}

//연산 프로퍼티
var dollorInPocket:Double{
    //접근자
    get{
        return Double(wonInPocket) / 1000.0
    }
    //설정자
    set{
        wonInPocket = Int(newValue * 1000.0)
        print("주머니의 달러를 \(newValue)달러로 변경 중입니다.")
    }
}

//주머니의 돈이 2000에서 3500원으로 변경될 예정입니다.
//주머니의 돈이 2000에서 3500원으로 변경되었습니다.
dollorInPocket = 3.5    //주머니의 달러를 3.5달러로 변경 중입니다.

 

 

타입 프로퍼티

 

위에서 알아본 프로퍼티 개념은 모두 타입을 정의하고 해당 타입의 인스턴스가 생성되었을 때 사용할 수 있는 인스턴스 프로퍼티입니다.

인스턴스 프로퍼티는 인스턴스를 새로 생성할 때마다 초깃값에 해당하는 값이 프로퍼티의 값이 되고, 인스턴스 마다 다른 값을 지닐 수 있습니다.
 
 #타입 프로퍼티 정의

각각의 인스턴스가 아닌 타입 자체에 속하는 프로퍼티를 타입 프로퍼티라고 합니다.

타입 프로퍼티는 타입 자체에 영향을 미치는 프로퍼티 입니다.

 #타입 프로퍼티 특징

인스턴스의 생성 여부와 상관 없이 타입 프로퍼티의 값은 하나이며, 그 타입의 모든 인스턴스가 공통으로 사용하는 값, 모든 인스턴스에서 공용으로 접근하고 값을 변경할 수 있는 변수 등을 정의할 때 유용합니다.
 

#타입 프로퍼티 종류
 1.저장 타입 프로퍼티 - 변수 또는 상수로 선언 할수 있다.

(반드시 초기값을 설정해야 하고, 지연 연산이 됩니다. 지연 저장 프로퍼티와는 다르게 다중 스레드 환경이라하더라도 단 한번만 초기화 된다는 보장을 받습니다.)
 
 2.연산 타입 프로퍼티 - 변수로만 선언할 수 있다.

아래 코드 처럼 타입 프로퍼티는 인스턴스를 생성하지 않고도 사용할 수 있으며, 타입에 해당하는 값입니다.
 

그래서 인스턴스에 접근할 필요 없이 타입 이름만으로도 프로퍼티를 사용할 수 있습니다.

 

class AClass{
    
    // 저장 타입 프로퍼티(변수)
    static var typeProperty:Int = 0
    
    // 저장 인스턴스 프로퍼티
    var instanceProperty:Int = 0{
        didSet{
            
            //*타입 변수 사용하기
            // Self.typeProperty 는
            // AClass.typeProperty와 같은 표현입니다.
            Self.typeProperty = instanceProperty + 100
        }
    }
    
    
    // 연산 타입 프로퍼티
    static var typeComputedProperty:Int {
        get{
            return typeProperty
        }
        set{
            typeProperty = newValue
        }
    }
}


AClass.typeProperty = 12345

// 12345
print(AClass.typeProperty)

let classInstance:AClass = AClass()
classInstance.instanceProperty = 100

// 200
print(AClass.typeProperty)
// 200
print(AClass.typeComputedProperty)



class Bcount{
    
    // 타입 상수
    static let dollarExchangeRate:Double = 1000.0
    
    // 저장 인스턴스 프로퍼티
    var credit:Int = 0
    
    
    // 연산 인스턴스 프로퍼티
    var dollarValue:Double{
        get{
            //*타입 상수 사용하기
            //Self.dollarExchangeRate 는
            //Bcount.dollarExchangeRate 와 같은 표현
            return Double(credit) / Bcount.dollarExchangeRate
        }
        set{
            credit = Int(newValue * Self.dollarExchangeRate)
            print("잔액을 \(newValue)달러로 변경 중입니다.")
        }
    }
    
    
}

 

test.zip
0.02MB