이번에는 프로퍼티에 대해서 조금 심오하게 알아보도록 하자.
프로퍼티
- 클래스, 구초제 또는 열거형 등에 관련된 값을 의미한다.
- 프로퍼티의 종류로는 저장 프로퍼티 / 연산 프로퍼티 / 타입 프로퍼티가 있다.
- 저장 프로퍼티 : 인스턴스의 변수 또는 상수
- 연산 프로퍼티 : 값을 지정하는 것이 아니라 특정 연산을 수행한 후 나오는 결과값을 의미한다.
- 타입 프로퍼티 : 특정 인스턴스에서 사용되는 프로퍼티가 아닌 특정 프로퍼티에서만 사용되는 프로퍼티를 의미
프로퍼티의 정의에 대해서 간단하게 알아봤고, 이렇게 글로만 작성할 경우에는 많이 헷갈릴 수 있음으로...
( 필자도 처음에 글로만 접했을 때는 아무것도 이해를 하지 못했다.. )
이렇게 대략적으로 프로퍼티에 대해서 알아봤고, 이제 하나하나 뜯어보면서 진행을 해보도록 하자.
저장프로퍼티는 프로퍼티를 사용하는 가장 간단한 방법이다.
대략적으로 저장 프로퍼티는 변수나 상수로 선언된 클래스나 구조체 인스턴스의 일부분으로 저장되는 것을 의미한다.
구조체와 클래스로 저장 프로퍼티에 대해서 알아보도록 하자.


우선 Human이라는 구조체를 만들었고, 그 안에 변수 name과 상수 gender를 String 타입으로 선언을 했다.
이렇게 구조체 내에서 선언된 변수나 상수를 저장 프로퍼티라고 한다.
그럼 이제 구조체를 인스턴스화하여 사용을 진행해보도록 하자.
human1이라는 인스턴스에 name 프로퍼티에는 "kim"을 gender 프로퍼티에는 "M"을 넣었다.
이렇게 인스턴스에 값이 저장되어 있는 것을 저장 프로퍼티로 이해하면 될 것 같다.
그럼 이제 선언된 인스턴스의 값을 변경해보도록 하자.

구조체의 gender 프로퍼티가 let으로 선언이 되어 있기 때문에 변경이 불가능하다.
인스턴스 자체를 변수로 선언을 했지만 구조체의 프로퍼티가 상수이기 때문에 변경이 불가능한 부분이다.
하지만 클래스에서는 값의 변경이 가능하다. 왜? 이전에 설명했다 싶이 구조체는 값 타입이고, 클래스는 참조 타입이기 때문이다.
이 부분은 클래스에 대해서 테스트를 진행할 때에 확인을 할 수 있을 것이다.
그럼 이제 반대로 인스턴스를 상수로 선언을 해서 사용을 해보도록 하자.

이렇게 구조체의 인스턴스를 상수로 선언을 할 경우에도 변경이 불가능하다.
쉽게 말해서 구조체의 프로퍼티 변경에 대한 우선 순위를 생각해보면 인스턴스 > 구조체 이 순서로 이해하면 될 것이다.
즉, 구조체의 경우에는 인스턴스의 선언이 우선으로 적용된다고 이해를 하면 될 것 같다.
정리를 해보면 name의 프로퍼티가 변수로 선언되어 있어도 구조체의 인스턴스가 상수이면 값을 변경할 경우에 에러가 발생하며,
human2의 인스턴스가 상수로 선언되어 있으면 애초에 변경이 불가능하다.
즉, 구조체 자체를 상수로 선언할 경우 내부 프로퍼티도 모두 상수로 변경된다고 생각하면 쉽게 이해가 될 것 같다.
그럼 이제 구조체의 경우에는 변경할 때에 에러가 생성되었는데 클래스는 어떻게 될까?
클래스는 위에서 언급했다 싶이 참조타입이어서 값의 변경이 가능하다.
소스를 통해서 테스트를 진행해보도록 하자.


좌측의 사진은 Dog 클래스를 선언했다. 이전에 진행했다 싶이 초기화도 같이 진행을 해줬다. init 구문에 대해서 이해가 되지 않을
경우에는 이전글을 참고해도 좋을 것 같다.
우측의 코드인 경우에는 dog1의 Dog클래스의 인스턴스를 선언했다. 변수타입으로 선언을 했으며, Class 안의 상수 gender에
대해서 변경을 하려고 했을 때에는 동일하게 에러가 발생한다.
그럼 위에서 말하는 구조체는 값 타입이고, 클래스는 참조 타입이기에 바뀔 수 있다는 내용이 잘못 된것 아니냐. 그런 의문이 들 수도 있다.
그럼 이제 반대로 테스트를 진행해보자.

위의 코드를 보면 확인이 되는 것과 같이 dog2를 상수 인스턴스로 선언을 진행했다.
하지만 dog2의 name이 변경이 가능한 내용을 확인할 수 있다.
앞에서 보면 구조체의 인스턴스를 let 즉, 상수로 선언했을 때에는 아예 변경을 할 수가 없었지만, 클래스의 경우에는
인스턴스가 상수로 선언이 되었고, 클래스 내부의 프로퍼티가 변수일 경우에는 참조 타입으로 인하여 값의 변경이 가능한 부분이다.
이런 부분이 구조체와 클래스의 간단한 차이라고 볼 수 있다. ( 실질적으로 간단하지 않다.. 충분한 연습이 필요하다 )
이렇게 값을 저장해서 사용하는 것을 쉽게 프로퍼티의 한 종류인 저장 프로퍼티라고 이해하면 될 것 같다.
그럼 이제 연산 프로퍼티에 대해서 확인을 해보도록 하자.
연산 프로퍼티는 동일하게 클래스, 구조체 열거형에서 사용이 가능하며, 연산 프로퍼티의 특징은
직접 값을 저장하지 않는 반면에 getter 와 setter를 사용해서 값을 활용하는 것을 의미한다.
JAVA 개발을 많이 해본 사람이라면 충분히 getter와 setter에 대한 지식이 있을 것이지만 이번에도 코드를 통해서 확인해보도록 하자.


product 구조체를 생성했다. 이 product 구조체는 평균값과 수량, 구매 금액을 표현하는 product 구조체이며,
이 구조체에서 getter와 setter를 사용하기 위해서는 함수를 호출하는 것과 같이 get과 set을 선언해주면 된다.
여기서 보이는 get과 set을 통해서 값을 전달하고 보여주는 것이 연산형 프로퍼티라고 할 수 있다.
그럼 이제 추가적인 예시를 통해서 확인을 해보도록 하자.

이렇게 필자의 경우에는 sales1 인스턴스에 평균값 3000과 수량 10을 받았다. 인스턴스를 선언하면서 왜 purchase가 없냐.
그런 의문이 들텐데 이 purchase 프로퍼티는 값을 활용하는 프로퍼티라서 따로 인스턴스 선언할 때에 값을 받지 않는다.
purchase를 호출했을 때에 왜 30,000이 나오는 이유는 purchase에 접근하게 되면 get 안에 있는 코드블럭이 실행되게 되기 때문이다.
이렇게 호출을 했을 때의 값을 저장하지 않고 사용할 수 있는 내용이 연산 프로퍼티라고 생각하면 된다.
( average * quantity 가 호출되어 30,000이 생성 )

우선적으로 purchase의 금액을 수정해봤다. 금액을 5000으로 값을 대입하였고, 이럴 경우에 set이 활성이 되어, newprice에
5000이 들어가면서 average가 500으로 변경된 내용을 확인할 수 있다.
get과 마찬가지로 purchase가 수정이 되게 되면, set 안에 있는 코드블럭이 실행되게 된다.
따라서 금액이 숭정된 평균인 500이 표기가 되는 부분이다.
연산프로퍼티는 인스턴스 내외부의 값을 연산해서 적절한 값을 전달해주는 접근자 역할이나 내부의 프로퍼티 값을 간접적으로 설정하는
설정자 역할을 할 수 있다.
참고로 연산프로퍼티에서 set을 지우고 get만 구현해서 읽지 전용으로도 사용할 수 이따.
이렇게 되면 연산 프로퍼티는 읽기 전용 프로퍼티로만 되어서 값을 변경할 수 없게 된다.

이렇게 매개변수를 setter에 설정을 해주지 않으면 새롭게 들어오는 값은 그냥 newValue라는 변수로 자동으로 사용이 가능하다.
이렇게 보통의 개발자들은 setter에 경우 특별하지 않으면 매개변수 이름을 설정하지 않고, 기본적인 값인 newValue를 활용한다.
그럼 이제 타입 프로퍼티에 대해서 알아보도록 하자.
타입 프로퍼티는 인스턴스 생성 없이 객체 내의 프로퍼티에 접근이 가능하다. 즉, 프로퍼티의 타입 자체와 연결 하는 것을 의미한다.
추가적으로 타입 프로퍼티는 static ( 정적 ) 으로 선언한다.


좌측에 TypeStructure의 구조체를 선언하였고, 이후에 static 변수의 프로퍼티를 생성했다.
이렇게 타입 프로퍼티로 선언된 프로퍼티에 접근하려면 인스턴스를 생성하지 않고, 타입 이름과 타입 프로퍼티로 접근을 할 수 있다.
타입 프로퍼티를 활용하면 변수에 클래스 할당에 대한 인스턴스를 생성하지 않아도 프로퍼티를 사용할 수 있다는 의미이다.
이렇게 3가지의 프로퍼티 종류에 대해서 알아보았다.
프로퍼티를 진행한 김에 프로퍼티 옵저버에 대한 추가적인 내용도 확인을 해보도록 하자.
프로퍼티 옵저버란 프로퍼티의 값을 관찰하고 반영하는 것을 의미한다.
즉, 새로운 값이 기존 값과 같더라도 프로퍼티 옵저버는 호출이 되며, 프로퍼티가 set 될 때마다 호출된다고 생각하면 된다.
프로퍼티 옵저버는 저장 프로퍼티, 오버라이딩이 된 저장 / 연산 프로퍼티에서만 사용이 가능하다.

Savings_Account 라는 적금 관련된 클래스를 생성하였다.
credit에 값이 들어갈 때마다 실행되는 프로퍼티 옵저버이다.
willSet 이란, 프로퍼티에 값이 저장되기 전에 호출하는 willSet 옵저버이다.
didSet 이란, 값이 저장된 직후에 호출하는 didSet 옵저버이다.
willSet 옵저버는 새로 변경될 값을 상수 매개변수로 지정하며, 위의 연산 프로퍼티에서 언급했다 싶이
매개변수의 이름을 지정할 수도 있고, 지정하지 않는 다면 newValue ( 새로운 값 )으로 자동 지정이 된다.
didSet 옵저버 또한 willSet 옵저버와 같이 동일하게 매개변수 이름을 지정할 수 있다.
만약 해당 부분에서 지정하지 않으면 oldValue로 자동으로 지정이 됨으로 oldValue와 newValue를 활용하면 된다.

myAccount 로 선언한 클래스 인스턴스를 생성했고, 이후에 myAccount.credit에 1000원을 입금했다.
값이 저장되기 전에 호출되는 willSet 프로퍼티 옵저버가 먼저 실행이 되었음으로
"잔액이 입고됬음으로 0원에서 1000로 변경될 예정입니다."
해당 부분이 먼저 실행되었고, 이후에 값이 저장되었음으로 "잔액이 0원에서 1000원으로 변경되었습니다."
해당 부분이 실행된 내용을 확인할 수 있다.
그럼 이제 다시한번 10,000원을 넣어보도록 해서 상황을 확인해보도록 하자.

이렇게 변수는 1개이지만 그전 값을 기억을 할 수 있는 부분이다.
이렇게 사용하는 기능이 바로 프로퍼티 옵저버의 역할이다.
이 부분을 활용한다면 간단하게 플레이 그라운드 만으로도 입출금 관련된 내용을 만들어 볼 수 있다.
즉, 프로퍼티의 종류에 대해서 통달한다면 은행 프로그램정도는 쉽게 만들 수 있다는 내용이다.
열심히 반복학습이 중요한 것 같다. ( 참고로 글을 작성하는 필자도 다양하게 활용할 수 있도록 열심히 노력해야겠다. )
'APPLE > Swift 문법' 카테고리의 다른 글
[ 기초 문법 ] 타입 캐스팅 (0) | 2022.08.16 |
---|---|
[ 기초 문법 ] 상속 (0) | 2022.08.14 |
[ 기초 문법 ] Init (0) | 2022.08.10 |
[ 기초 문법 ] 구조체와 클래스 (0) | 2022.08.09 |
[ 기초 문법 ] 옵셔널 (0) | 2022.08.08 |