initialization 톺아보기(1) — 값 타입 초기화

kangYundol
daily-monster
Published in
10 min readApr 6, 2024

initialization 톺아보기(1) — 값 타입 초기화
initialization 톺아보기(2) — 클래스 초기화
initialization 톺아보기(3) — 2단계 초기화와 클래스 상속

안녕하세요 토요일 윤돌이입니다! 오늘은 Swift의 Initialization에 대해 정리해보았습니다.

항상 사용하지만 한 번도 제대로 정리해본적이 없는 것 같아서 이번 기회에 한 번 짚고 넘어가려해요!

Initialization 내용은 크게

  1. Struct(값 타입) Initialization
  2. Class(참조 타입) Initialization
  3. failable, required Initialization

로 세 번에 걸쳐 정리할 예정입니다.

오늘은 Initialization의 기본과 Struct Initialization에 대해 알아보아요.

모든 내용은 Swift.org의 내용을 참고하였습니다!

Initializers

초기화의 정의를 먼저 알아봅시다.

초기화란 클래스, 구조체, 열거형의 인스턴스를 생성하는 것으로 프로퍼티 초기값을 설정하고 인스턴스를 사용하기 전에 다른 설정을 하는 것도 포함됩니다.

중요한 것은 초기화 시점에 모든 프로퍼티 값이 지정되어있지 않다면 초기화가 실패된 것으로 인스턴스가 생성되지 않습니다‼️

init() {
// 초기화 작업 진행
}

저장 프로퍼티의 초기값 설정

1️⃣ init을 사용한 초기값 설정

클래스와 구조체는 인스턴스가 생성되기 전에 모든 프로퍼티 초기값을 반드시 설정해야한다고 했습니다.

예시로 7살 유치원생 친구들을 생성해볼게요.

struct Human {
var age: Int
init() {
age = 7
}
}

var kindergartner = Human()
print("유치원생의 나이는 \(kindergartner.age)살 입니다.")

Human 구조체는 age라는 저장 프로퍼티를 하나 가지고 있고 init 구문에서 age의 초기값을 지정해주고 있습니다.

2️⃣ 프로퍼티 선언시 초기값 설정

struct Human {
var age: Int = 7
}

하지만 이렇게 init을 사용하지 않고도 바로 초기값을 지정해줄 수 있습니다.

만약에 프로퍼티가 항상 같은 초기값을 갖는 경우 방법2️⃣을 사용하는 것이 더 좋다고 합니다!

이 방법이 더 명확하고 기본값으로부터 프로퍼티 타입을 유추하기 쉽기 때문이에요.

Customaizng Initialization

init에 파라미터를 생성하여 값 지정할 수도 있습니다.

struct Area {
var shapeArea: Double

init(rectWidth: Double, rectHeight: Double) {
shapeArea = rectWidth * rectHeight
}

init (triWidht: Doucle, triHeight: Double) {
shapeArea = (triWidht * triHeight) / 2
}
}

let rectangle = Area(rectWidht: 10.0, rectHeight: 10.0) // 100.0
let triangle = Area(triWidth: 10.0, triHeight: 10.0) // 50.0

init은 메소드 이름이 모두 동일하기 때문에 Initialization의 파라미터명이 정말 중요합니다❕
따라서 인수라벨이 정의된 경우에는 반드시 사용되어야 해요.

만약 인수라벨을 사용하고 싶지 않다면 일반 메소드와 같이 언더바(_) 를 사용해주세요!

init(_ width: Double, _ height: Double) {
shapeArea = rectWidth * rectHeight
}

옵셔널 프로퍼티

Initialization 과정에서 값을 정할 수 없거나 추후에 지정되는 경우 옵셔널 프로퍼티를 사용할 수 있습니다.

옵셔널 프로퍼티는 자동적으로 nil 값을 가지기 때문에 init 구문에서 초기값을 지정해주지 않아도 됩니다!

struct Teacher {
var subject: String?
var name: String

init(name: String) {
self.name = name
}

func teacherInfo() {
print("이름: \(name)")
}
}

let teacher = Teacher(name: "윤돌이")
teacher.teacherInfo() // 이름: 윤돌이
teacher.subject = "Swift"

subject 프로퍼티는 옵셔널 값이기 때문에 init 구문에서 초기화값을 지정하지 않아도 인스턴스를 생성할 수 있습니다.

Default Initializers

반드시 init이 없어도 기본 초기화가 가능합니다. swift에서는 모든 프로퍼티의 기본값이 지정되어있고 init이 하나도 정의되어있지 않은 경우 기본 initializer를 제공합니다.

이를 default initializer라고 합니다. default initializer는 모든 프로퍼티가 기본값으로 설정된 새로운 인스턴스를 생성합니다.

class Car {
var name: String?
var price = 1000000
var purchased = false
}
var car = Car()

Car의 모든 프로퍼티는 기본값을 가지고 있고 상속받는 클래스가 없기 때문에 모든 프로퍼티가 기본값을 가지고 있습니다. 옵셔널 값의 경우 nil을 자동으로 할당받게 됩니다!

따라서 default initializer를 가질 수 있습니다.

여기까지 기본적인 Initializers의 특징을 살펴보았습니다.
이렇다면 이 내용을 바탕으로 구조체 초기화에 대해 알아봅시다🙌

Memberwise Initializers

구조체의 경우 custom init을 만들지 않으면 자동으로 memberwise initializer를 사용할 수 있습니다.

struct Size {
var width = 0.0
var height = 0.0
}

let rectSize = Size(width: 1.0, height: 1.0)

Size는 두 개의 프로퍼티를 가지고 프로퍼티는 모두 초기화되어있습니다.

0.0이라는 초기값을 통해 두 프로퍼티는 Double로 타입추론 되고 init(width: height:)라는 memberwise initializer를 받게 됩니다.

init()이 없어도 자동으로 모든 프로퍼티의 값을 설정할 수 있도록 해주는 것이죠!

memberwise initializer는 기본값이 있는 프로퍼티는 생략할 수 있습니다.

let circleSize = Size(height: 3.0)
let zeroSize = Size()

memberwise initializer는 이 밖에도 몇 가지 특징을 가지고 있습니다.

✅ memberwise initializer는 파라미터가 프로퍼티가 선언된 순서와 개수에 맞게 생성됩니다.

struct Size {
var width = 0.0
var height = 0.0
}

let rectSize = Size(height: 1.0, width: 1.0) // ‼️ Error

✅ 프로퍼티가 상수로 선언되어있고 이미 초기값을 가진 경우에는 생성자 목록에서 제외됩니다.

struct Size {
let width = 1.0
var height = 0.0
}

let rectSize = Size(height: 1.0)

✅ 프로퍼티 중 하나라도 private인 경우 memberwise initializer가 제공되지 않습니다.

struct Size {
private var width = 1.0
var height = 0.0
}

// memberwise init 제공되지 않음

Initializer Delegation

initializer는 인스턴스 초기화를 위해 다른 initializer를 호출할 수도 있습니다. 이를 initializer delegation라고 합니다.

initializer delegation는 여러 초기화 구문에서 코드가 중복되는 것을 방지해주고 값타입과 참조타입에서 모두 가능합니다.

값 타입(구조체와 열거형)에서는 상속을 지원하지 않고 initializer delegation을 자신이 제공하는 다른 initializer에만 위임할 수 있기 때문에 간단합니다.

struct Human {
var age = 20
var name = "윤돌"
}
struct Book {
var price = 0
var name = "Swift"
}
struct Reader {
var book = Book()
var human = Human()

// 1️⃣
init() {}

// 2️⃣
init(book: Book, human: Human) {
self.book = book
self.human = human
}

// 3️⃣
init(book: Book, owner: Human) {
let bookName = "\\(owner.name)이 읽는 책"
let bookPrice = book.price * (100 - owner.age)/100
self.init(book: Book(price: bookPrice, name: bookName),
human: owner)
}
}

1️⃣ 첫번째 initializer인 init()은 custom initializer가 없는 경우 사용됩니다. {}에 아무 내용이 없는 빈 본문을 가지게 됩니다.

이 initializer를 호출하면 Book(price: 0, name: “Swift”)와 Human(age: 20, name: “윤돌”) 기본값으로 초기화되는 Reader()를 반환합니다.

let reader = Reader()
print(book.price) // 0
print(book.name) // Swift
print(human.age) // 20
print(human.name) // 윤돌

2️⃣ 두번째 initializer인 init(book: human:)은 Reader 구조체에서 custom initializer가 없으면 memberwise initializer와 똑같이 동작합니다.

let reader = Reader(book: Book(price: 10000, name: "initializer 공부하기"),
human: Human(age: 25, name: "김춘배")

3️⃣ 세 번째 initializer는 human을 기반으로 book의 프로퍼티값을 지정합니다.

값 타입의 경우 custom initializer를 작성할 때 같은 값 타입으로부터 다른 initializer를 참조하기 위해 self.init을 사용합니다. self.init 은 초기화 구문 내에서만 호출할 수 있습니다. 실제로 3️⃣번 init 내부에서 self.init으로 2️⃣번 init을 호출하는 것을 볼 수 있습니다.

// 3️⃣
init(book: Book, owner: Human) {
let bookName = "\\(owner.name)이 읽는 책"
let bookPrice = book.price * (100 - owner.age)/100
self.init(book: Book(price: bookPrice, name: bookName),
human: owner)
}


// 인스턴스 생성

let reader = Reader(book: Book(price: 10000, name: "initializer 공부하기"),
owner: Human(age: 25, name: "김춘배"))

여기까지 초기화 기본과 값타입에서의 초기화에 대해 알아보았습니다!

다음주에는 참조 타입의 초기화에 대해 알아보겠습니다.

오류나 잘못된 내용이 있다면 언제든 댓글로 피드백 부탁드립니다~!

[참고]

https://bbiguduk.gitbook.io/swift/language-guide-1/initialization

--

--