본문 바로가기
swift

스위프트 초기화 구문

by 승환파크 2024. 4. 16.

구조체나 클래스는 항상 인스턴스를 생성해서 메모리 공간을 할당받은 다음에 사용해야 한다. 이를 초기화라고 한다. 초기화 과정에서 모든 저장 프로퍼티는 초기화되어야 하며 기본 초기화 구문을 사용할 때 저장 프로퍼티에 초기값이 지정되어 있어야 한다.

Resolution()
Video()
Location()

 

하지만 멤버와이즈 초기화 구문을 알고 있다. 초기화 괄호 안에 인자를 넣어서 초기화하는 방식이다. 하지만 이는 구조체에서 멤버와이즈 초기화만 가능하고 클래스에서는 불가능하다. 또한 구조체에서 멤버와이즈 초기화 구문에서 일부 변수만 외부값으로 초기화 할 때, 또는 클래스에서 외부값으로 초기화를 하는 상황이 나올 수 있다. 이 때 사용하는 것을 생성자 라고 한다.

 

init 초기화 메소드

아래는 초기화 메소드의 형식이다.

init(<매개변수> : <타입>, <매개변수> : <타입>, ...) {
    1. 매개변수 초기화
    2. 인스턴스 생성 시 기타 처리할 내용
}

 

위 구문의 특징을 정리하면 다음과 같다.

1. 초기화 메소드의 이름은 init으로 통일된다.

만일 다른 이름이 사용되거나 대소문자가 바뀌면 초기화 메소드로 인지하지 못한다.

2. 매개변수의 갯수, 이름, 타입은 임의로 정의할 수 있다.

단, 메소드에 정의된 매개변수의 순서와 형식에 따라 인스턴스 생성 과정에서 넣어야 하는 인자값의 순서와 형식이 결정된다.

3. 매개변수의 이름과 개수, 타입이 서로 다른 여러 개의 초기화 메소드를 정의할 수 있다.

오버로딩된 메소드는 스위프트에서 서로 다른 메소드로 간주되기 때문에, 이같은 특성을 이용하면 다양한 형식을 갖는 초기화 메소드를 정의할 수 있다.

4. 정의된 초기화 메소드는 직접 호출되기도 하지만, 대부분 인스턴스 생성 시 간접적으로 호출된다.

초기화 구문이 여러 개 정의되어 있을 경우 인스턴스 생성 구문과 매개변수 형식이 일치하는 초기화 메소드가 호출된다. 만약 인스턴스 생성 구문의 형식과 일치하는 초기화 메소드가 정의되지 않았다면 오류가 발생한다.

 

아래는 예제 코드이다.

struct Resolution {
    var width = 0
    var height = 0
    
    init(width: Int) {
        self.width = width
    }
}

class VideoMode {
    var resolution = Resolution(width: 4096)
    var interlaced = false
    var frameRate = 0.0
    var name: String?
    
    // 초기화될 때 name 인자값만 받는 init 구문
    init(name: String) {
        self.name = name
    }
    
    // 초기화될 때 interlaced 인자값만 받는 init 구문
    init(interlaced: Bool) {
        self.interlaced = interlaced
    }
    
    // 초기화될 때 interlaced, frameRate 두 개의 인자값을 받는 init 구문
    init(interlaced: Bool, frameRate: Double) {
        self.interlaced = interlaced
        self.frameRate = frameRate
    }
    
    // 초기화될 때 interlace, frameRate, name 세 개의 인자값을 받는 init 구문
    init(interlaced: Bool, frameRate: Double, name: String) {
        self.interlaced = interlaced
        self.frameRate = frameRate
        self.name = name
    }
    
}

let nameVideoMode = VideoMode(name: "홍길동")
let simpleVideoMode = VideoMode(interlaced: true)
let doubleVideoMode = VideoMode(interlaced: true, frameRate: 40.0)
let tripVideoMode = VideoMode(interlaced: true, frameRate: 40.0, name: "홍길동")

let defaultVideoMode = VideoMode() // Error

 

위와 같이 초기화할 수 있다. 주의할 것은 init 메소드가 작성되고 나면 기본 초기화 구문은 더는 제공되지 않는다. 기본 초기화 구문을 사용하면 에러가 발생한다. 만약 기본 초기화 구문을 사용하고 싶다면 기본 초기화 구문을 추가해야 한다.

class VideoMode {
	... 중략 ...
    
    // 기본 초기화 구문
    init() {
    }
}

 

우리는 '기본 초기화 구문 + 이름을 받는 초기화 구문' 두 개의 기능을 하는 구문을 만들 수 있다.

class VideoMode {
	... 중략 ...
    
    init(name: String = "") {
    	self.name = name
    }
}

let defaultVideoMode = VideoMode() // 가능
let nameVideoMode = VideoMode("홍길동") // 가능

 

초기화 구문의 오버라이딩

클래스에서 초기화 구문도 일종의 메소드이므로, 자식 클래스에서 오버라이딩이 가능하다. 아래는 예시 코드이다.

class Base {
    
}

class ExBase: Base {
    override init() {
        
    }
}

 

Base 클래스에 초기화 구문이 선언되지 않았다면 기본 초기화 구문을 갖고 있으므로 자식 클래스 ExBase에서 부모의 기본 초기화 구문을 override 할 수 있다. 초기화 구문을 오버라이딩하면 더 이상 부모 클래스에서 정의한 초기화 구문이 실행되지 않는다. 만약 부모 클래스의 기본 초기화 구문에서 프로퍼티를 초기화했다면, 자식 클래스에 기본 초기화 구문을 오버라이딩함으로써 부모 클래스 프로퍼티의 초기화가 누락된다. 부모 클래스에서 정의된 초기화 구문을 내부적으로 호출하려면 super.init 구문을 작성하면 된다.

class Base {
    var baseValue: Double
    
    init(inputValue: Double) {
        self.baseValue = inputValue
    }
}

class ExBase: Base {
    override init(inputValue: Double) {
        super.init(inputValue: 10.5)
    }
}

 

BaseValue 프로퍼티는 옵셔널 타입이 아닌 일반 타입이므로 반드시 초기값이 있어야 하지만 초기화 구문의 오버라이딩으로 인해 초기값 할당 구문이 누락되면 오류가 발생한다. 이러한 오류를 방지하기 위해 오버라이딩된 초기화 구문에서 부모 클래스의 초기화 구문을 직접 호출해주게 된다. 초기화 구문의 호출 순서는 자식 초기화 구문 호출 -> 부모 초기화 구문 호출 순으로 이루어진다. 만약 A, B, C 클래스가 있을 때, B가 A를 상속하고, C가 B를 상속하고, 초기화 구문에서 각각 부모의 초기화 구문을 호출한다면, 'C 초기화 구문 호출 -> B 초기화 구문 호출 -> A 초기화 구문 호출' 순으로 이루어진다.

'swift' 카테고리의 다른 글

스위프트 Interface Builder 와 UI 구성  (0) 2024.04.19
스위프트 옵셔널 체인  (0) 2024.04.16
스위프트 타입 캐스팅  (1) 2024.04.16
스위프트 상속  (1) 2024.04.16
스위프트 메소드  (0) 2024.04.16