소멸자(Deinitialization)
- 소멸자는 클래스 인스턴스가 메모리에서 제거되기 직전에 실행되는 코드 블록을 의미한다
- 소멸자를 정의하여 인스턴스가 사라지기 전에 필요한 정리 작업을 수행할 수 있다
- Swift는 자동 참조 카운팅(ARC)을 사용하여 메모리를 관리하기 때문에 대부분의 경우 소멸자를 사용하지 않아도 된다
- 그러나, 파일을 닫거나 네트워크 연결을 해제하는 등 특정 작업의 정리가 필요한 경우 소멸자를 사용한다
소멸자의 특징
- 클래스에만 존재하며, 구조체와 열거형에는 사용할 수 없다
- 클래스마다 하나의 소멸자만 정의할 수 있다 (
deinit 키워드를 사용)
- 소멸자는 파라미터를 사용하지 않으며, 반환 값도 없다
- 인스턴스가 메모리에서 제거되기 직전에 자동으로 호출된다
- 소멸자는 명시적으로 호출할 수 없다 (자동으로 호출됨)
- 상속 관계가 있는 경우, 하위 클래스의 소멸자가 호출된 후 상위 클래스의 소멸자가 자동으로 호출된다
소멸자 기본 사용 방법
- 소멸자는 클래스 인스턴스가 더 이상 필요 없거나 강한 참조가 모두 제거될 때 자동으로 호출된다
- 기본 사용 방법으로는 인스턴스를 nil로 설정하여 메모리에서 제거되도록 하는 방식이 있다
- 인스턴스의 소멸 여부는 ARC(Automatic Reference Counting)에 의해 결정된다
소멸자 기본 사용 예시
class Logger {
var message: String
init(message: String) {
self.message = message
print("Logger 생성: \(message)")
}
deinit {
print("Logger 소멸: \(message)")
}
}
var logger: Logger? = Logger(message: "파일 기록 중...")
logger = nil
- 이 예제는 가장 기본적인 소멸자 사용 예시이다
Logger 클래스는 message라는 저장 속성을 가진다
init() 메서드는 인스턴스가 생성될 때 메시지를 출력한다
- 소멸자
deinit은 인스턴스가 메모리에서 제거되기 직전에 메시지를 출력한다
logger = nil을 설정하면 소멸자가 자동으로 호출된다
소멸자의 일반적인 사용 예시 (특별한 작업 수행 시 필요)
- 인스턴스가 사라질 때 특별한 정리 작업이 필요할 경우 소멸자를 사용한다
- 예를 들어, 파일을 열고 데이터를 쓰는 경우 파일을 닫아야 파일이 손상되지 않는다
- 네트워크 연결이 유지되는 경우, 인스턴스가 사라지기 전에 연결을 종료해야 할 수도 있다
파일 처리 예제
class FileWriter {
var fileName: String
var isFileOpen: Bool = false
init(fileName: String) {
self.fileName = fileName
openFile()
}
func openFile() {
isFileOpen = true
print("\(fileName) 파일을 열었습니다.")
}
func closeFile() {
isFileOpen = false
print("\(fileName) 파일을 닫았습니다.")
}
deinit {
if isFileOpen {
closeFile()
}
}
}
var writer: FileWriter? = FileWriter(fileName: "Data.txt")
writer = nil
FileWriter 클래스는 fileName과 isFileOpen이라는 저장 속성을 가진다
- 인스턴스가 생성되면 파일이 자동으로 열리며 (
openFile() 메서드 호출), 상태는 isFileOpen = true가 된다
- 소멸자
deinit은 파일이 열린 상태일 때(isFileOpen == true), 파일을 닫는 메서드(closeFile())를 호출한다
- 인스턴스를
nil로 설정하면 소멸자가 호출되며 열린 파일이 닫힌다
- 파일을 안전하게 닫도록 보장하는 방식이다
소멸자와 상속 관계 (상속이 있는 경우의 소멸자 호출 규칙)
- 상위 클래스의 소멸자는 하위 클래스의 소멸자가 호출된 후에 자동으로 호출된다
- 하위 클래스가 자체적인 소멸자를 제공하지 않더라도 상위 클래스의 소멸자는 항상 호출된다
- 이 과정은 상위 클래스의 모든 정리 작업이 완료되도록 보장한다
상속 관계에서의 소멸자 예시
class NetworkManager {
var connectionName: String
init(connectionName: String) {
self.connectionName = connectionName
print("\(connectionName) 연결을 시작합니다.")
}
deinit {
print("\(connectionName) 연결이 종료되었습니다.")
}
}
class WebSocketManager: NetworkManager {
var socketID: String
init(connectionName: String, socketID: String) {
self.socketID = socketID
super.init(connectionName: connectionName)
print("웹소켓 연결 설정됨. Socket ID: \(socketID)")
}
deinit {
print("웹소켓 연결 해제됨. Socket ID: \(socketID)")
}
}
var manager: WebSocketManager? = WebSocketManager(connectionName: "Main Server", socketID: "ABC123")
manager = nil
NetworkManager는 네트워크 연결을 관리하며, 소멸자가 연결 종료 메시지를 출력한다
WebSocketManager는 NetworkManager를 상속하여 웹소켓 연결을 추가로 관리한다
- 인스턴스를
nil로 설정하면 하위 클래스의 소멸자가 호출된 후 상위 클래스의 소멸자가 호출된다
요약
- 소멸자는 인스턴스가 메모리에서 제거되기 직전에 자동으로 호출되는 메서드이다
deinit 키워드를 사용하여 정의하며, 클래스마다 하나만 존재할 수 있다
- 소멸자는 파일 닫기, 네트워크 연결 해제 등 중요한 정리 작업을 수행하는 데 사용된다