초기화는 단순히 객체를 '만드는' 과정을 넘어, 인스턴스가 사용되기 전에 모든 저장 프로퍼티가 적절한 초기 값을 가지도록 보장하는 중요한 역할을 합니다. 이는 Swift의 강력한 타입 안전성 원칙의 핵심이며, 여러분의 앱에서 발생할 수 있는 잠재적인 오류를 미리 방지하는 데 필수적입니다.
1. 초기화(Initialization)란 무엇인가요?
초기화는 클래스, 구조체, 또는 열거형의 새로운 인스턴스를 생성할 준비를 하는 과정입니다. 이 과정에서 새로운 인스턴스의 모든 저장 프로퍼티는 반드시 초깃값을 할당받아야 합니다.
초기화를 수행하는 특별한 메서드를 초기화 메서드(Initializer)라고 하며, init 키워드를 사용합니다. Swift는 모든 저장 프로퍼티에 초깃값이 할당되기 전까지는 인스턴스를 사용할 수 없도록 강제하여 잠재적인 오류를 방지합니다.
💡 왜 초기화가 중요한가요?
만약 인스턴스의 특정 프로퍼티가 초기화되지 않은 상태로 사용된다면, 이는 예측 불가능한 동작이나 앱 크래시로 이어질 수 있습니다. 초기화는 이러한 불안정한 상태를 원천 봉쇄하여 코드의 안정성을 극대화합니다.
1.1. 초기화 메서드 (Initializers)
init 키워드를 사용하여 초기화 메서드를 정의합니다. 함수와 유사하지만, 반환 타입이 없으며 인스턴스 자신을 반환합니다.
//Swift 예제
struct Fahrenheit {
var temperature: Double
// 초기화 메서드 정의
init() {
temperature = 32.0 // 기본값으로 초기화
}
init(celsius: Double) { // 외부에서 섭씨 온도를 받아 초기화
temperature = celsius * 1.8 + 32.0
}
init(fahrenheit: Double) { // 외부에서 화씨 온도를 받아 초기화
temperature = fahrenheit
}
}
// 초기화 메서드 호출
let f1 = Fahrenheit() // init() 호출
print("기본 온도: \(f1.temperature)°F") // 출력: 기본 온도: 32.0°F
let f2 = Fahrenheit(celsius: 25.0) // init(celsius:) 호출
print("섭씨 25도: \(f2.temperature)°F") // 출력: 섭씨 25도: 77.0°F
let f3 = Fahrenheit(fahrenheit: 98.6) // init(fahrenheit:) 호출
print("화씨 98.6도: \(f3.temperature)°F") // 출력: 화씨 98.6도: 98.6°F
2. 매개변수 이름과 인자 레이블
초기화 메서드의 매개변수도 함수처럼 외부 매개변수 이름(인자 레이블)을 가질 수 있습니다. 기본적으로 첫 번째 매개변수를 제외하고는 매개변수 이름이 인자 레이블로 사용됩니다.
//Swift 예제
struct Color {
let red, green, blue: Double
// 명시적인 인자 레이블 사용
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
// 인자 레이블을 생략하고 싶을 때 `_` 사용
init(_ white: Double) { // 외부에서 white라는 레이블 없이 호출 가능
red = white
green = white
blue = white
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
print("마젠타 색상: R=\(magenta.red), G=\(magenta.green), B=\(magenta.blue)")
// 출력: 마젠타 색상: R=1.0, G=0.0, B=1.0
let halfGray = Color(0.5) // _white 초기화 호출
print("회색 색상: R=\(halfGray.red), G=\(halfGray.green), B=\(halfGray.blue)")
// 출력: 회색 색상: R=0.5, G=0.5, B=0.5
3. 초기화 위임 (Initializer Delegation)
3.1. 구조체의 초기화 위임
//Swift 예제
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
init() {} // 기본 초기화 메서드
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size) // 다른 init 호출 (위임)
}
}
let basicRect = Rect() // init() 호출
print("기본 사각형: \(basicRect.origin), \(basicRect.size)") // 출력: 기본 사각형: Point(x: 0.0, y: 0.0), Size(width: 0.0, height: 0.0)
let customRect = Rect(origin: Point(x: 10.0, y: 10.0), size: Size(width: 50.0, height: 50.0)) // init(origin:size:) 호출
print("커스텀 사각형: \(customRect.origin), \(customRect.size)")
let centerRect = Rect(center: Point(x: 50.0, y: 50.0), size: Size(width: 100.0, height: 100.0)) // init(center:size:) 호출 -> init(origin:size:)으로 위임
print("중심으로 만든 사각형: \(centerRect.origin), \(centerRect.size)")
3.2. 클래스의 초기화 위임 (지정 초기화와 편의 초기화)
클래스 초기화는 구조체보다 복잡합니다. 지정 초기화(Designated Initializer)는 클래스의 모든 프로퍼티를 완전히 초기화하는 주된 초기화 메서드입니다. 편의 초기화(Convenience Initializer)는 지정 초기화 메서드를 호출하여 초기화 과정을 보조하는 보조 초기화 메서드입니다.
두 가지 초기화 위임 규칙:
- 지정 초기화는 반드시 직계 수퍼클래스의 지정 초기화를 호출해야 합니다.
- 편의 초기화는 반드시 동일 클래스의 다른 초기화 메서드를 호출해야 합니다. (결국 지정 초기화로 이어져야 함)
//Swift 예제
class Vehicle {
var numberOfWheels: Int
var maxPassengers: Int
// 지정 초기화
init(numberOfWheels: Int, maxPassengers: Int) {
self0.numberOfWheels = numberOfWheels
self.maxPassengers = maxPassengers
}
// 편의 초기화 (동일 클래스의 다른 초기화 호출)
convenience init(singleWheelVehicle: Bool) {
if singleWheelVehicle {
self.init(numberOfWheels: 1, maxPassengers: 1)
} else {
self.init(numberOfWheels: 4, maxPassengers: 4)
}
}
}
class Bicycle: Vehicle {
var hasBasket: Bool
// 지정 초기화 (수퍼클래스의 지정 초기화 호출)
init(hasBasket: Bool) {
self.hasBasket = hasBasket
super.init(numberOfWheels: 2, maxPassengers: 1) // Vehicle의 지정 초기화 호출
}
// 편의 초기화 (동일 클래스의 다른 초기화 호출)
convenience init() {
self.init(hasBasket: false) // Bicycle의 지정 초기화 호출
}
}
let unicycle = Vehicle(singleWheelVehicle: true) // 편의 초기화 호출
print("외발 자전거 바퀴: \(unicycle.numberOfWheels), 승객: \(unicycle.maxPassengers)") // 1, 1
let myBicycle = Bicycle(hasBasket: true) // Bicycle의 지정 초기화 호출
print("내 자전거 바구니: \(myBicycle.hasBasket), 바퀴: \(myBicycle.numberOfWheels)") // true, 2
let normalBicycle = Bicycle() // Bicycle의 편의 초기화 호출
print("일반 자전거 바구니: \(normalBicycle.hasBasket), 바퀴: \(normalBicycle.numberOfWheels)") // false, 2
4. 실패 가능한 초기화 (Failable Initializers): nil을 반환할 수 있는 초기화
//Swift 예제
struct MenuItem {
let name: String
// 실패 가능한 초기화 (빈 문자열이거나 유효하지 않은 항목이면 실패)
init?(name: String) {
if name.isEmpty { // 이름이 비어있으면 초기화 실패
return nil
}
self.name = name
}
}
if let pizza = MenuItem(name: "피자") {
print("메뉴 항목 생성 성공: \(pizza.name)") // 출력: 메뉴 항목 생성 성공: 피자
} else {
print("메뉴 항목 생성 실패.")
}
if let emptyItem = MenuItem(name: "") { // 이름이 비어있으므로 nil 반환
print("메뉴 항목 생성 성공: \(emptyItem.name)")
} else {
print("메뉴 항목 생성 실패.") // 출력: 메뉴 항목 생성 실패.
}
5. 디이니셜라이저 (Deinitializers): 인스턴스 해제 시 정리 작업
//Swift 예제
class Bank {
static var coinsInBank = 10_000 // 은행이 보유한 코인 총량
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToDistribute = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToDistribute
return numberOfCoinsToDistribute
}
static func receive(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
deinit { // 플레이어 인스턴스가 해제될 때 호출
Bank.receive(coins: coinsInPurse) // 보유 코인을 은행으로 반환
}
}
var playerOne: Player? = Player(coins: 100) // 플레이어 생성, 100코인 받음
print("은행에 남은 코인: \(Bank.coinsInBank)") // 9900
print("플레이어1이 가진 코인: \(playerOne!.coinsInPurse)") // 100
playerOne = nil // playerOne이 nil이 되면서 인스턴스 해제, deinit 호출
print("은행에 남은 코인: \(Bank.coinsInBank)") // 10000 (코인이 다시 은행으로 돌아옴)
정리하며
- init 메서드: 인스턴스의 모든 저장 프로퍼티를 초깃값으로 설정하는 필수적인 과정입니다.
- 초기화 위임: 구조체는 self.init(), 클래스는 지정 초기화와 편의 초기화를 통해 코드 중복을 줄입니다.
- 실패 가능한 초기화(init?): 특정 조건에서 인스턴스 생성이 실패할 경우 nil을 반환합니다.
- 디이니셜라이저(deinit): 클래스 인스턴스가 메모리에서 해제될 때 정리 작업을 수행합니다.
0 comments:
댓글 쓰기