참고로 ‘마무리’ 라는 용어는 개인적으로 멋대로 부르는 것이고 정확히 뭐라 불러야 할지는 잘 모르겠다. :-)
Initialization
생성자(Constructor) 개념은 클래스가 객체화 될 때 자동으로 실행되는 메소드를 지칭한다. 스위프트의 초기화 혹은 생성자는
init
이라는 키워드의 메소드가 담당한다. 이 init
은 구조체(struct)와 클래스(class) 모두에서 지원되는 기능이다. Objective-C로 코딩을 해 봤다면 아주 익숙한 이름일 것이다.init()
은 일반 메소드 정의와는 다르게 func
라는 키워드가 필요없다. 그러니 일반 메소드와는 다르다고 생각하자.
class SimpleClass { var value = 0 init(v: Int) { self.value = v } }이름에 걸맡게
init
메소드는 초기화 작업 전반을 담당하면 된다.init
은 클래스나 구조체의 인스턴스를 생성 할 때의 넘기는 매개변수 구조에 따라 호출되는 것이 다르다.class SimpleClass { var value = 0 init(v: Int) { self.value = v } init() { self.value = -999 } }두 개의
init
이 오버로드 되어있다. 하지만 매개변수가 다르다. 특히 하나는 매개변수가 존재하지 않는다. 이 매개변수 없는 init()
은 기본 초기화 메소드(Default Initialization)로 아래과 같이 그냥 인스턴스를 생성하면 호출된다.
var instance = SimpleClass()
물론 인자를 넣어서 다른 초기화 메소드를 이용하는 것도 가능하다.
var instance = SimpleClass(v: 50)
init()
이 다른 메소드와 다른점은 모든 매개변수에 별명이 붙는다는 점이다. 위 처럼 모든 매개변수 별명을 호출 시 적어줘야 한다. 하지만 메소드와 비슷하게 init도 별명 생략 기능을 이용 할 수 있다.
class SimpleClass { var value = 0 init(_ v: Int) { self.value = v } init() { self.value = -999 } } let a = SimpleClass(10) // {value 10} let b = SimpleClass() // {value -999}별명을 필요없다고 선언된 init이 오버로드된 경우도 잘 돌아간다.
상속 시
init
도 그대로 상속된다. 또한 init
을 오버라이드 할 때 super의
init을 호출하는 것으로 부모의 초기화 메소드를 그대로 이용 할 수 있다. 다만, init
은 오버라이드 시 override
를 표기할 필요가 없다.
class AnotherClass: SimpleClass { init() { super.init() } } var instance = AnotherClass() // instance.value == -999물론
super.init()
을 호출하지 않아도 위 예제는 문제는 없겠지만, 상속 시 부모의 생성자(초기화 메소드)를 호출하지 않으면 대게 문제가 발생할 여지가 높다. 기억해두자.앞서
init()
은 오버로드가 가능하다고 설명했었다. 그런데 한 클래스의 init에서 자신의 다른 init을 호출하면 오류가 발생한다. 앞에서 본 SimpleClass를 다시 수정해보자.
class SimpleClass { var value = 0 init(v: Int) { self.value = v } init() { self.init(v: -999) // ERROR! } }기본 초기화 메소드인
init()
을 수정했다. 의도는 이전과 동일한 결과를 내려고 하는 것인데, 문제는 self.init(v: Int)
를 호출하려는 과정이 오류로 표시된다. 스위프트의 또다른 제약인 셈이다.물론 해법을 제공해주고 있다.
convenience
(편의)라는 이름의 키워드를 정의하면 가능하다.
class SimpleClass { var value = 0 init(v: Int) { self.value = v } convenience init() { self.init(v: -999) } }이렇게 하면 기본 생성자인
init()
은 이제 init(v: Int)
초기화 메소드를 이용해 초기화를 진행 할 수 있게 된다.convenience
키워드는 한 init이 다른 init을 호출하는 식으로 init이 여러 단계에 걸쳐서 처리(이른바 multi-step initialization)해야 할 때 필요한 키워드이다.Deinitialization
기존 OOP의 파괴자(Destructor)와 비슷한 마무리 용도의 기능으로
deinit
이 있다. Objective-C의 dealloc 메소드와 비슷한 용도이다. 이름 만으로도 판단이 가능하겠지만 init의 반대 요소이다.참고로 deinit은 클래스에서만 사용이 가능하다는 점에 주의하자.
deinit 은 메소드라 하기엔 좀 모양이 다르다. 앞서 살펴본 SimpleClass를 좀 뜯어고친 예제를 보자.
class SimpleClass { var value = 0 deinit { self.value = 0 } }
deinit
은 매개변수를 가질 수 없다. 스위프트에서 파괴자는 메소드의 형태가 아니라는 말이다. 뭐 그래도 하는 역활은 파괴자 메소드와 별 차이가 없어보이긴 한다. 대게 프로그래머가 직접 파괴자를 호출하도록 코드를 짤 수 없기 때문에 대부분의 OOP용 언어에서 파괴자는 매개변수가 존재하지 않는다.간략히 정리하자면,
deinit
은 클래스 인스턴스가 필요없어져 메모리에서 사라질 때 (즉 레퍼런스 카운트가 0이 될 때) 호출되는 기능이다. 주로 자신이 점찍어 놓은(retain) 다른 인스턴스의 메모리가 해제 될 수 있도록 조치(release) 해 주는 것이 목적이지만, 스위프트는 ARC기반 하에 있어서 이런 행위는 거의 필요없다.아마도 스위프트에서
deinit
은 싱글턴 인스턴스 등이 자신의 인스턴스를 활용하고 있다면 해당 싱글턴 인스턴스에서 자신을 참조하지 않도록 처리하는데 주로 사용되지 않을까 생각된다. 물론 한가지 예일 뿐이지 그 사용 용도는 적재적소에 맞게 구현하면 된다.[관련글] Swift - 클래스(Class) 훑어보기
[관련글] Swift - 구조체(Structure) 훑어보기
[관련글] Swift - 메소드(Method)
[돌아가기] 스위프트(Swift) 가이드
0 comments:
댓글 쓰기