인스턴스 생성 및 소멸

Gooreum·2021년 10월 28일
0

Swift

목록 보기
12/16

초기화(initialization)는 클래스나 구조체 또는 열거형의 인스턴스를 사용하기 위한 준비 과정이다.

이번 장에서는 인스턴스를 생성하는 방법과 클래스의 인스턴스가 소멸할 때 어떤 프로세스가 진행되는지 알아보자.

인스턴스 생성

  • 초기화 과정은 새로운 인스턴스를 사용할 준비를 하기 위하여 저장 프로퍼티초깃값을 설정하는 등의 일을 한다.
    • 이니셜라이저(initializer)를 정의하면 초기화 과정을 직접 구현할 수 있다.
    • 스위프트의 이니셜라이저는 반환 값이 없다.
    • 이니셜라이저의 역할은 그저 인스턴스의 첫 사용을 위해 초기화하는 것뿐이다.
  • 이니셜라이저는 func 키워드를 사용하지 않고 오로지 init 키워드를 사용하여 이니셜라이저 메서드임을 표현한다.
    • init 메서드는 클래스, 구조체, 열거형 등의 구현부 또는 해당 타입의 익스텐션 구현부에 위치한다.
    • 다만 클래스의 지정 이니셜라이저는 익스텐션에서 구현해줄 수 없다.

프로퍼티 기본값

  • 구조체와 클래스의 인스턴스는 처음 생성할 때 옵셔널 저장 프로퍼티를 제외한 모든 저장 프로퍼티에 적절한 초깃값(initial value)을 할당해야 한다.
    • 초기화 후에 값이 확정되지 않은 저장 프로퍼티는 존재할 수 없다.
    • 프로퍼티를 정의할 때 프로퍼티 기본값(default value)을 할당하면 이니셜라이저에서 따로 초깃값을 할당하지 않더라도 프로퍼티 기본값으로 저장 프로퍼티의 값이 초기화된다.
  • 초기화와 프로퍼티 감시자
    • 이니셜라이저를 통해 초깃값을 할당하거나, 프로퍼티 기본값을 통해 처음의 저장 프로퍼티가 초기화될 때는 프로퍼티 감시자 메서드가 호출되지 않는다.

      class SomeClass {
      	var value: Int = 0 {
      		willSet {
      			print("\(value) will be changed to \(newValue)")
      		}
      		didSet {
      			print("\(oldValue) has been changed to \(value)")
      		}
      	}
      	
      	init() {
      		self.value = 30
      		print("property is initialized")
      	}
      }
      //출력 : 프로퍼티 감시자 내부 메서드는 작동하지 않는다는 것을 알 수 있따.
      property is initialized
      30

이니셜라이저 매개변수

  • 함수나 메서드를 정의할 때와 마찬가지로 이니셜라이저도 매개변수를 가질 수 있다.

옵셔널 프로퍼티 타입

  • 초기화 과정에서 값을 초기화하지 않아도 되는, 즉 인스턴스가 사용되는 동안에 값을 꼭 갖지 않아도 되는 저장 프로퍼티가 있다면 해당 프로퍼티를 옵셔널로 선언할 수 있다.
    • 옵셔널로 선언한 저장 프로퍼티는 초기화 과정에서 값을 할당해주지 않는다면 자동으로 nil이 할당된다.

상수 프로퍼티

  • 상수로 선언된 저장 프로퍼티는 인스턴스를 초기화하는 과정에서만 값을 할당할 수 있으며, 처음 할당된 이후로는 값을 변경할 수 없다.
  • *상수 프로퍼티와 상속
    • 클래스의 인스턴스의 상수 프로퍼티는 프로퍼티가 정의된 클래스에서만 초기화할 수 있다.
    • 해당 클래스를 상속받은 자식클래스의 이니셜라이저에서는 부모클래스의 상수 프로퍼티 값을 초기화할 수 없다.

기본 이니셜라이저와 멤버와이즈 이니셜라이저

  • 사용자 정의 이니셜라이저를 정의해주지 않으면 클래스나 구조체는 모든 프로퍼티에 기본값이 지정되어 있다는 전제하에 기본 이니셜라이저를 사용한다.
    • 기본 이니셜라이저는 프로퍼티 기본값으로 프로퍼티를 초기화해서 인스턴스를 생성한다.
    • 즉, 기본 이니셜라이저는 저장 프로퍼티의 기본값이 모두 지정되어 있고, 동시에 사용자 정의 이니셜라이저가 정의되어 있지 않은 상태에서 제공된다.
  • 구조체는 사용자 정의 이니셜라이저를 구현하지 않으면 프로퍼티의 이름으로 매개변수를 갖는 이니셜라이저인 멤버와이즈 이니셜라이저를 기본으로 제공한다.
    • 그러나 클래스는 멤버와이즈 이니셜라이저를 지원하지 않는다.
  • 구조체에서 사용자 정의 이니셜라이저를 정의하면, 멤버와이즈 이니셜라이저를 사용할 수 없다.
    • 사용자 정의 이니셜라이저를 정의할 때도 기본 이니셜라이저나 멤버와이즈 이니셜라이저를 사용하고 싶다면 익스텐션을 사용하여 사용자 정의 이니셜라이저를 구현하면 된다.

초기화 위임

  • 구조체와 열거형은 코드의 중복을 피하기 위하여 이니셜라이저가 다른 이니셜라이저에게 일부 초기화를 위임하는 초기화 위임을 간단하게 구현할 수 있다.
    • 하지만 클래스는 상속을 지원하는 터라 간단한 초기화 위임도 할 수 없다.
      import Foundation
      
      enum Student {
      	case elementary, middle, high
      	case none
      
      	init() {
      	self = .none
      	}
      	
      	init(koreanAge: Int) {
      		switch koreanAge {
      			case 8...13 :
      				self = .elementary
      			case 14...16 :
      				self = .middle
      			case 17...19 :
      				self = .high
      			default :
      				self = .none
      		}
      	}
      	
      	//allocate initializer	
      	init(bornAt: Int, currentYear: Int) {
      		self.init(koreanAge: currentYear - bornAt + 1)
      	}
      }
      
      //middle
      var younger: Student = Student(koreanAge: 16)
      print(younger)
      //high
      younger = Student(bornAt: 1998, currentYear: 2016)
      print(younger)
      //none
      younger = Student(bornAt: 1990, currentYear: 2021)
      print(younger)

실패 가능한 이니셜라이저

  • 이니셜라이저를 통해 인스턴스를 초기화할 수 없는 여러 가지 예외 상황이 있다.
    • 이니셜라이저를 정의할 때 이런 실패 가능성을 염두에 두기도 하는데, 이렇게 실패 가능성을 내포한 이니셜라이저를 실패 가능한 이니셜라이저(failable initializer)라고 부른다.
    • 실패 가능한 이니셜라이저는 클래스, 구조체, 열거형 등에 모두 정의할 수 있다.
    • 실패 가능한 이니셜라이저는 실패했을 때 nil을 반환해주므로 반환 타입이 옵셔널로 지정된다.
    • 따라서 실패 가능한 이니셜라이저는 init 대신에 init? 키워드를 사용한다.
  • 실패 가능한 이니셜라이저는 구조체와 클래스에서도 유용하지만 특히 열거형에서 유용하게 사용할 수 있다.
    • 특히 case에 맞지 않는 값이 들어오면 생성에 실패할 수 있다.

함수를 사용한 프로퍼티 기본값 설정 -

  • 사용자 정의 연산을 통해 저장 프로퍼티 기본값을 설정하고자 한다면 클로저나 함수를 사용하여 프로퍼티 기본값을 제공할 수 있다.
    • 인스턴스를 초기화할 때 함수나 클로저가 호출되면서 연산 결괏값을 프로퍼티 기본값으로 제공해준다.
    • 그렇기 때문에 클로저나 함수의 반환 타입은 프로퍼티의 타입과 일치해야 한다.

인스턴스 소멸

  • 클래스의 인스턴스는 디이니셜라이저(Deinitializer)를 구현할 수 있다.
    • 메모리에서 해제되기 직전 클래스 인스턴스와 관련하여 원하는 정리 작업을 구현할 수 있다.
    • 디이니셜라이저는 클래스의 인스턴스가 메모리에서 소멸되기 바로 직전 호출된다.
    • deinit 키워드를 사용하여 디이니셜라이저를 구현하면 자동으로 호출된다.
    • 디이니셜라이저는 클래스의 인스턴스에만 구현할 수 이 있다.
  • 클래스에는 디이니셜라이저를 단 하나만 구현할 수 있다.
  • 디이니셜라이저는 이니셜라이저와는 다르게 매개변수를 갖지 않으며, 소괄호도 적어주지 않는다.
  • 또, 자동으로 호출되기 때문에 별도의 코드로 호출할 수도 없다.
profile
하루하루 꾸준히

0개의 댓글