기어가더라도 제대로
[Swift-기초] class - 100 days of swiftUI 본문
목차
1. class 생성 방법
2. 상속하는 방법
3. class 에 initializer 추가하기
4. class copy
5. class deinitializer
6. class의 property 가 어떻게 변하는가?
등을 알아봅시다.
class VS. struct (기초)
- 생성방법이 struct 와 비슷, 중요한 점에서 차이 "class" 키워드를 붙이느냐, "struct" 키워드를 붙이느냐 차이
- 공통점
- 타입을 생성하고 이름 부여
- 속성, 메서드, 프로퍼티 감시자, 접근 제어를 할 수 있음
- 원하는 방식으로 initializer를 커스텀하게 구현가능
- 차이점
- 바탕이 되는 class의 기능위에 또다른 class 를 만들 수 있다. 혹은 선택적으로 override 할 수도 있다.
- 완벽하게 따라가는게 아니기 때문에, super의 생성자를 sub 에서 자동으로 생성해주지는 않는다. initialize 는 각자 해야한다.
- class의 인스턴스를 복사하게 되면 그안에 프로퍼티와 같은 데이터도 같이 복사된다. 복사본의 프로퍼티를 변경하면 원본도 변경
- class 인스턴스의 마지막 복사본이 파괴되면, Swift 가 선택적으로 deinitializer 라는 메서드를 호출한다.
- class 자체를 상수로 선언하더라도, 프로퍼티가 변수로 선언되어있으면 변경가능하다.
class 가 사용되는 이유(struct와 차이점 심화)
- class A 가 class B 를 상속받고 class B 는 클래스 C를 상속받고, 클래스 C는 클래스 D를 상속받는 것이 가능
- 상속관계를 유지하는 클래스간에 공통된 initializer 가 없는 이유는, 특정 클래스 X 에서 프로퍼티를 하나라도 추가하면 모든 초기화 생성자를 깨트릴 것이기 때문
- 원본과 복사본의 관계에서, 한 인스턴스의 속성값을 변경하면 모든 복사본의 속성값이 변경됩니다.
- class의 인스턴스가 어디서든 참조될 수 있으므로 최종 복사본이 파괴되었는지가 중요해집니다.
클래스가 클래스를 상속하는 방법
- 상속
- 존재하는 클래스를 기반으로 해서 새로운 클래스를 생성하는 절차
- 물려주면 부모, 혹은 super // 물려 받으면 child class 혹은 subclass
- 약간의 수정만 해주면 하위 클래스에서 상속받을 수 있음
이런 클래스가 를 상속받고 싶다면 이 클래스를 상속받으려는 클래스를 선언할 때 ":(콜론)" 뒤에 부모 클래스를 쓰면됨
Employee 를 상속받는 클래스들은 hours 프로퍼티나 initializer 를 별도의 선언 없이 사용할 수 있음
- hours 를 공유할 뿐만 아니라 Employee에서 메서드도 공유할 수 있다.
물려받은 메서드도 하위 클래스에서 입맛에 맞게 변경할 수 있는데, "override" 키워드를 사용한다.
override func printSummary() {
print("I'm a developer who will sometimes work \(hours) hours a day, but other times spend hours arguing about whether code should be indented using tabs or spaces.")
}
Developer 클래스에서만 재정의 해준 모습
- 클래스를 상속시키지 않을 것이라면 class 앞에 "final" 키워드를 붙이면 된다.
클래스 initializer를 생성하는 방법
- struct initializer 보다 조금 까다롭긴한데
- "자식 클래스가 자신의 프로퍼티를 모두 초기화한 후에 부모의 initializer를 호출해야한다"
- 클래스는 공통된 initializer가 없음
- 클래스마다 initializer 를 만들어주어야 함(혹은 모든 프로퍼티를 디폴트 값으로 초기화 하거나)
- isElectric 이라는 bool 변수 하나 가 있으니 초기화 하기위해 생성자에서도 bool 타입의 인자를 받아야함
- 생성자 안에서 self는 자기 자신의 프로퍼티를 의미한다.
- 추가로 bool 타입 변수인 inConvertible 을 생성
- 생성자에서 이 변수를 위한 매개변수가 추가된 모습
- 근데 여기서 마무리 하면 부모 클래스의 초기화를 할 수 없어서 에러가 날 것임
- isElectric, isConvertible 생성자로 두개의 파라미터를 받음
- 하나는 자신의 프로퍼티 초기화에, 다른 하나는 부모 클래스의 프로퍼티 초기화에 사용
- super
- self 키워드랑 비슷
- 부모클래스의 생성자, 메서드, 프로퍼티에 접근할 수 있도록 Swift에서 자동으로 제공
성공한 모습. 만약 자식 클래스에서 별다른 프로퍼티를 초기화하지 않을 경우엔 부모 클래스의 생성자를 자동으로 물려받아 쓴다.
class 복사
- 복사한 클래스간에는 같은 데이터를 공유
- 한 복사본의 프로퍼티가 업데이트되면 다른 원본 및 복사본에 영향
- class 가 참조 타입(reference type)이기 때문에 발생하는 현상
- 클래스의 모든 복사본은 기저에 같은 데이터를 기반으로함
- class 복사를 알아보기 위한 간단한 실험
- 원본 user1 을 복사본 user2에 복사한 후, user2 의 프로퍼티를 업데이트하고나서 원래의 프로퍼티를 보는 실험
"Taylor" 가 두번찍힌다.
바꾸지않은 인스턴스의 값도 바뀌는 현상이 버그 같지만 기능이다.
이 기능은 공통의 데이터를 앱 전체에서 공유할 수 있도록 해주기 때문이다. SwiftUI 는 Data 의 타입의 경우 class에 많이 의존하는데 공유가 매우 쉽기 때문이다.
복사는 하지만 따로 데이터를 들고 싶다면 DeepCopy 라는 것을 이용해야한다.
- 코드를 보면 copy() 메서드가 User를 리턴하는 것을 볼 수 있는데,
- 이는 공유되는 user가 아니라 프로퍼티의 값만 동일한 새로운 User 를 생성하는 것이다.
- 추후에 복사본의 값을 바꾸면 변경된 값이 공유되지 않을 것이다.
deinitializer 생성
- class 가 생성될 때 호출되는 initializer 의 반대 개념
- 의무적이진 않음
- 고유함 - func 로 선언 X
- 파라메터, 리턴값, () X
- 마지막 복사본이 파괴되면 자동 호출
- 절대 직접 deinitializer 를 호출 X, 시스템이 호출
- struct 는 deinitializer X, 복사본이 없기 때문(하나하나가 원본)
간단한 실험
- Scope 의 개념
- if 문 안에 선언한 변수는 밖에서 접근 불가
- for 문 마찬가지
- 함수 안에 선언한 변수 밖에서 접근 불가
- 이번엔 for문의 Scope 를 이용해서 deinitailzer 실험
- Scope 의 지역성에 의해서 For 문이 끝나는 동시에 생성한 각각의 User 인스턴스는 deinitializer 를 호출 할 것 임
- for 문이 끝나는 시점이 아닌, 배열의 값이 clear 되는 순간 User 인스턴스들이 deinitializer 될것임
var 변수가 class 내부에서 동작하는 방법
- class의 복사본들은 이정표처럼 원본의 데이터를 가리킴
- 복사본 중 하나가 값을 변경할 경우 모두 그 변경된 데이터를 참조함
- 이를 이해 하기 위해 클래스가 var 변수를 어떻게 대하는지 알 필요가 있음
- 인스턴스의 var 변수 변경 O
- let 으로 선언된 user 인스턴스 변경 X
- 비유하자면, user 라는 표지판을 새웠는데 그 표지판에 이름만 바꿔 단 것임
- 표지판이 향하고 있는 방향은 여전히 그대로고, 그 내부의 정보만 바뀜
- 즉, let 으로 선언된 user 가 바뀐 것은 아님 - 내부 데이터는 바뀜
- name 을 let으로 선언하면 ? 지워지지 않는 잉크로 표지판에 새겼기 때문에 안바뀜
- 인스턴스도 var, 변수도 var 로 선언하면 어떻게 될까?
- 프린트 결과 Paul 이 찍힐 것임
- name 은 "Taylor" 로 바꿧지만, user 객체를 새로운 인스턴스로 갈아끼웠기 때문에 다시 "Paul" 로 초기화 됨
- 인스턴스 var - name let 으로 하면, 인스턴스는 갈아낄 수 있는데 값은 변경 못함
- 프로퍼티가 var 면
- 변경 가능
- 언젠가 변경 될 수 있음을 허용
- 인스턴스가 상수이든 변수이든 변경에 열려있음
- 프로퍼티가 let 이면
- 변경 불가
- 변경의 가능성 X
- struct 와 차이
- struct 는 mutating 을 붙여야 함수가 var 프로퍼티 변경 가능
- class 는 그런 것 없음
- 클래스는 변수의 인스턴스가 let 이든 var 이든 프로퍼티를 변경 가능
- struct 는 내부의 data 를 바꾸려고 하면 암시적으로는 struct 의 인스턴스 자체를 바꾼다.
이 실험은 user1 을 Person 스트럭트로 만들고, user2 에 복사를 하고 한번 출력
user2 의 name 을 변경하고 다시 출력 한 실험이다.
복사만 하였을 땐 user1 과 user2가 같다고 표시를 했지만,
user2의 값을 변경하였을 땐 서로 다른 객채라고 한다.
Person 의 name 프로퍼티가 변경되면 인스턴스 자체가 변경된 것과 같다.
결론은 class 는 내부의 값이 달라져도 그 인스턴스의 identity 에는 영향을 주지 않지만,
struct 는 내부의 값이 달라지면 그 자체로 다른 인스턴스가 되어버린다.
'Swift - 기초' 카테고리의 다른 글
[Swift-기초] Extension, protocol Extension - 100 days of SwiftUI (0) | 2022.10.02 |
---|---|
[Swift - 기초] Protocol, Opaque return type(some) (0) | 2022.10.01 |
[Swift - 기초] 100 Days of SwiftUI - Day 11, 접근 제어자, Static 키워드 (0) | 2022.09.29 |
[10일차] struct (0) | 2022.09.28 |
[8일차] 클로저 (0) | 2022.09.28 |