← 메인으로

0802 클래스 초기화, 소멸

클래스의 인스턴스를 생성할 때 다음과 같이 초기화가 가능하다.

var account1 = BankAccount(number: 122, balance: 400.54) 

[!note] 근데 궁금한 점이 있다. 저런 값은 할당 연산자 = 으로 주는게 맞지 않나? 왜 : 으로 값을 주는 걸까?

혼동 포인트

일반적인 값 대입은 = 쓰는 게 맞다.

var score = 100 // score에 100을 대입 

근데 : 는 완전히 다른 역할이다.

var account1 = BankAccount(number: 122, balance: 400.54) 

결론적으로, = 는 값을 할당하는 것, : 는 매개변수에 이름을 붙여서 값을 전달하는 것. Swift는 가독성과 실수를 줄이기 위한 언어이기 때문에 무슨 값이 어디에 들어가는지 명확하게 보이게 하는 걸 중요하게 생각한다.

: 는 대입이 아니라, "이 값은 이 이름의 매개변수에 해당됩니다."라고 알려주는 레이블 역할이다.


소멸자

스위프트 런타임 시스템에 의해 클래스 인스턴스가 없어지기 전에 해야 할 정리 작업은 클래스 안에 소멸자를 구현하면 가능하다.

class BankAccount { var accountBalance: Float = 0 var accountNumber: Int = 0 init(number: Int, balance: Float) { accountNumber = number accountBalance = balance } deinit { //필요한 정리 작업을 여기서 수행한다. } } 

클래스 인스턴스를 "초기화"한다는 건?

클래스를 만들면 그 안에 값을 넣을 수 있는 공간(프로퍼티)이 생긴다. 근데 그걸 처음에 어떤 값으로 시작할 지 정해줘야 한다.

인스턴스를 "소멸"시킨다는 건?

Swift에서는 클래스 인스턴스가 더 이상 필요없을 때 자동으로 메모리에서 지워진다. 이걸 ARC(Automatic Reference Counting)라고 한다.

class BankAccount { var accountNumber: Int init(number: Int) { accountNumber = number print("계좌 \(accountNumber) 생성됨") } deinit { print("계좌 \(accountNumber) 해지됨") } } 
var account: BankAccount? = BankAccount(number: 1111) account = nil // 여기서 인스턴스가 사라지면서 deinit 실행됨 

메서드 호출하기와 프로퍼티 접근하기

이쯤에서 지금까지 우리가 무엇을 했는지 돌이켜보자. 우리는 BankAccount라는 이름의 새로운 스위프트 클래스를 만들었다. 이 클래스에 은행 계좌번호와 잔액을 담기 위한 프로퍼티들을 선언했고, 현재의 잔액을 표시하기 위한 메서드도 선언했다.

앞 절에서는 새로운 클래스의 인스턴스를 생성하고 초기화하는 데 필요한 작업을 공부했다. 다음에 할 것은 우리가 만든 클래스에 있는 인스턴스 메서드를 어떻게 호출하며, 프로퍼티엔 어떻게 접근하는지를 배울 차례다.

이것은 점 표기법을 이용하면 정말 쉽다.

var balance1 = account1.accountBalance 
account1.accountBalance = 544.45 
account1.displayBalance() 
class BankAccount { ... class func getMaxBalance() -> Float { return 10000.00 } } 
var maxAllowed = BankAccount.getMaxBalance // 10000.00이 할당 

갑자기 또 훅 들어온다. ㅋㅋㅋㅋ 게터는 뭐고 세터는 뭐야 ㅋㅋㅋㅋㅋ


게터와 세터(getter, setter)

게터와 세터는 프로퍼티의 값을 읽거나 설정할 때 실행되는 특별한 함수다.

저장 프로퍼티일 때

var name: String = "James" 

연산 프로퍼티일 때

var fullName: String { get { return firstName + " " + lastName } set(newValue) { let parts = newValue.split(seperator: " ") firstName = String(parts[0]) lastName = String(parts[1]) } } 

BankAccount 예제에서

var balanceLessFees: Float { get { return accountBalance - fees } } 

저장 프로퍼티와 연산 프로퍼티

스위프트의 클래스 프로퍼티는 저장 프로퍼티와 연산 프로퍼티로 나뉜다. 저장 프로퍼티는 상수나 변수에 담기는 값이다. BankAccount 예제에서 계좌 이름과 번호 프로퍼티 모두는 저장 프로퍼티다.

반면, 연산 프로퍼티는 프로퍼티에 값을 설정하거나 가져오는 시점에서 어떤 계산이나 로직에 따라 처리된 값이다. 연산 프로퍼티는 게터(getter)를 생성하고 선택적으로는 세터(setter)메서드를 생성하며, 연산을 수행할 코드가 포함된다.

예를 들어, BankAccount 클래스에 은행 수수료를 뺀 현재 잔액을 담는 프로퍼티가 추가로 필요하다고 해보자. 저장 프로퍼티를 이용하는 대신에 값에 대한 요청이 있을 때마다 계산되는 연산 프로퍼티를 이용하는 것이 더 좋겠다.

그러니까, "수수료를 뺀 잔액"이라는 정보가 필요할 때, 그 값을 따로 저장해두는 게 아니라 필요할 때마다 자동으로 계산해서 보여주는 게 더 좋다! -> 이게 바로 "연산 프로퍼티"를 쓰는 이유. 예를 들어 이해해보자.

var balanceLessFees: Float = accountBalance - fees 
var blanceLessFees: Float { get { return accountBalance - fees } } 

이제 BankAccount 클래스는 다음과 같이 수정된다.

class BankAccount { var accountBalance: Float = 0 var accountNumber: Int = 0 let fees: Float = 25.00 var balanceLessFees: Float { get { return accountBalance - fees } } init(number: Int, balance: Float) { accountNumber = number accountBalance = balance } } 
var balanceLessFees: Float { get { return accountBalance - fees } set(newBalance) { accountBalance = newBalance - fees } } 
var balance1 = account1.balanceLessFees account1.balanceLessFees = 12123.12 

[!note] 그러니까 이건... 저장 프로퍼티가 실시간으로 값을 반영하지 못하고 고정되는 것의 한계를 극복하기 위한 방법으로써의 연산 프로퍼티라고 생각하면 되려나?

지연 저장 프로퍼티