Initializers(초기화)
- 소들님의 블로그를 참고하여 작성한 글입니다.
‼️제일 중요‼️
생성자 메서드가 종료되기 전까지, 생성자 안에 모든 프로퍼티는 초기값을 지니고 있어야 한다
구조체의 초기화
1. 프로퍼티에 기본 값 넣어주기
- 선언과 동시에 기본 값을 넣어주어 초기화하기
struct Human {
let name: String = "Miro"
let age: Int = 28
}
2. 프로퍼티 타입을 Optional로 하기
- 초기화를 할 때 Optional 타입의 프로퍼티는 nil로 초기화가 된다.
struct Human {
let name: String?
let age: Int?
}
3. init 함수(생성자) 활용하기
struct Human {
let name: String
let age: Int
init(name: String) {
self.name = name
self.age = 28
}
}
4. Memberwise Initializers 활용하기
- 구조체가 자동으로 제공하는 생성자(init 함수)
4-1. Memberwise Initializers(초기 값이 존재한다면?)
- var 로 선언된 프로퍼티라면?
- init함수로 값을 변경시킬 수 있다.
struct Human {
var name: String = "Miro"
}
Human.init() // name이 제외된 생성자
Human.init(name: "Miro") // name을 초기화 시킬 수 있는 생성자
- let 으로 선언된 프로퍼티라면?
- 해당 프로퍼티는 생성자의 프로퍼티에서 제외가 된다.
struct Human {
let name: String = "Miro"
let age: Int
}
Human.init(age: 28)
4-2. Memberwise Initializers(init함수를 직접 생성해준다면?)
- struct안에서 init함수를 생성해주면, 따로 memberwise initializer가 제공되지 않는다.
- 단, extension을 활용하면 직접 정의한 init함수와 memberwise initializers를 활용할 수 있다.
4-3. Memberwise Initializers(private 프로퍼티가 존재한다면?)
- 한 개라도 private 프로퍼티가 존재한다면, memberwise initializer는 제공되지 않는다.
클래스의 초기화
1. 프로퍼티에 기본 값 넣어주기
class Human {
let name: String = "Miro"
let age: Int = 28
}
2. 프로퍼티 타입을 Optional로 하기
- 단, let 으로 선언한 경우 기본 값을 주지 않으면 에러가 생기게된다.
class Human {
var name: String?
var age: Int?
}
3. init 함수(생성자) 활용하기
class Human {
var name: String?
let nickName: String = "Miro"
let age: Int
init(name: String) {
self.age = 28
}
}
3-1. init 함수(생성자) - 지정 생성자
- 클래스의 모든 프로퍼티를 초기화 하는 생성자
class Human {
let name: String
let age: Int
init(name: String) {
self.name = name
self.age = 28
}
}
- 만약, 상속 받은 클래스의 지정 생성자를 작성할 경우, 슈퍼 클래스의 생성자를 호출해야된다.
- 아래와 같이 init 안에서 슈퍼 클래스의 생성자를 호출해준다.
class Human {
let name: String
init(name: String) {
self.name = name
}
}
class Miro: Human {
let alias: String
init(alias: String) {
self.alias = alias
super.init(name: alias)
}
}
3-1. init 함수(생성자) - 편의 생성자
- 모든 프로퍼티를 초기화 할 필요는 없는 생성자이자, 지정 생성자를 보조해주는 생성자
- 같은 클래스에 있는 초기화 생성자(init)를 호출 시켜야된다.
- 결과적으로 모든 프로퍼티를 초기화 해주는 지정 생성자를 호출한다!
- 편의 생성자는 같은 클래스에 있는 편의 생성자를 호출할 수 있다. 그러나 호출된 편의 생성자는 최종적으로 지정 생성자를 호출해야된다.
class Miro {
var name: String
var nickName: String
init(name: String, nickName: String) {
self.name = name
self.nickName = nickName
}
convenience init(name: String) {
self.init(name: name, nickName: "미로")
}
}
Initializer Delegation
값 타입의 Initializer Delegation
- 생성자에서 다른 생성자를 호출하여 초기화 코드의 중복을 제거하는 방법!
- 유지 보수가 쉬워진다
struct Position {
var x: Int
var y: Int
init(xPos: Int, yPos: Int) {
x = xPos
y = yPos
}
init(pos: Int) {
self.init(xPos: pos, yPos: pos)
}
}
참조 타입의 Initializer Delegation
Delegate Up
- Designated Initializer(지정 생성자)는 반드시 슈퍼 클래스의 Designated Initializer(지정 생성자)를 호출해야 합니다
Delegate Across
- Convenience Initializer(편의 생성자)는 동일한 계층의 생성자를 호출해야된다.
- 최종적으로는 동일 계층의 Designated initializer를 호출해야된다.
클래스의 1단계 초기화
- 지정 초기화를 생성할 경우, super 클래스의 지정 초기화를 반드시 호출해야된다. 즉, 자신의 윗 클래스들이 다 타고타고 다 초기화 되어야한다!
- 타고타고 올라가서 더 이상 초기화가 될 슈퍼 클래스가 존재하지 않으면 그때 1단계 초기화가 끝난다.
클래스의 2단계 초기화
- init 함수 안에서, 자신의 프로퍼티에 접근을 하고 싶다면 super.init()이후에 접근을 해라!
Initializer의 상속
- 서브 클래스에 알아서 Initializer가 상속되는 조건 두 가지
- 서브 클래스에서 지정 초기화를 직접 구현하지 않았을 때(서브 클래스의 프로퍼티에 기본 값이 존재할 경우) → init을 정의하지 않으니 지정 초기화를 직접 구현하지 않는다.
override의 활용
- 무조건 super 를 호출해야된다.
class Human {
var name: String
init(name: String) {
self.name = name
}
}
class Miro: Human {
var nickName: String = "Miro"
var age: Int
override init(name: String) {
// 무조건 super를 호출해야된다.
self.age = 19
super.init(name: "")
}
}
Required init
- 필수 생성자로, 슈퍼 클래스에서 정의해둘 경우 서브 클래스가 슈퍼 클래스의 생성자를 상속받지 않는 한
서브클래스에서 반드시 구현해주어야한다.
- 즉, 서브 클래스에서 반드시 구현해야되는 생성자일 경우, 슈퍼 클래스에서 required init으로 설정을 해둔다.
- 아래와 같이 슈퍼 클래스가 required init을 구현했다면?
class Person {
var name: String?
required init(name: String) {
self.name = name
}
}
- 무조건, 아래와 같이 서브 클래스는 required init을 슈퍼 클래스와 동일한 형태로 구현해줘야된다.(단, override 키워드는 붙혀주지 ❌)
class Miro: Person {
var age: Int
init(age: Int) {
self.age = age
super.init(name: "")
}
required init(name: String) {
print("Skrrrrt")
}
}
- 단, required init은 서브 클래스에서 지정 생성자를 직접 구현했을 때만 필요하다.
NSCoding
A protocol that enables an object to be encoded and decoded for archiving and distribution.
- 우리가 required init 를 UIView와 UIViewController를 상속받는 서브 클래스를 만들 때 자주 본다.
- 그 이유는 UIView, UIViewController는 NSCoding 프로토콜을 채택하기 때문이다.
- Storyboard를 통하여 만든 UI 형태는 XML 형태로 저장된다. 이런 XML을 가져오기 위한 메소드가 init(coder: NSCoder) 이다.
- 근데, Storyboard로만 진행을하면 따로 지정 생성자를 만들지 않기에 지정 생성자를 구현해주지 않는다. 그러나, 코드로 뷰를 생성할 경우 지정 생성자를 만들기 때문에, required init 를 구현해줘야된다.
Failable Initializers
- 원래 생성자가 초기화를 실패할 경우, 에러를 던져야하지만 failable initializer의 경우, 에러가 아닌 nil을 던진다.
- initialier의 옵셔널 버전이다.
- 단, failable initializer를 통하여 생성된 인스턴스의 경우 옵셔널 타입이다!
대표적인 failable initializer
init?() {
...
}
'Swift' 카테고리의 다른 글
[Swift] IUO(옵셔널 암시적 추출) (0) | 2023.06.12 |
---|---|
[Swift] self는 언제 쓸까? (0) | 2023.04.13 |
[Swift] Closure (0) | 2023.03.09 |
[Swift] Enumeration(열거형) (0) | 2023.03.06 |
[Swift] mutating (0) | 2023.02.24 |