Lesson 66Classes
Deinitializers
What are Deinitializers?
A deinit is called immediately before a class instance is deallocated. Use it to clean up resources like closing files, invalidating timers, or disconnecting from services.
Deinit Syntax
class MyClass {
deinit {
// Cleanup code here
}
}
deinit {
// Cleanup code here
}
}
Common Use Cases
Close Files
Release file handles and streams
Disconnect
Close database/network connections
Stop Timers
Invalidate scheduled timers
Remove Observers
Unsubscribe from notifications
Key Points
- Classes ONLY (structs don't have deinit)
- Called automatically by Swift (ARC)
- No parameters, no parentheses
- Superclass deinit called automatically after subclass deinit
main.swift
// DEINITIALIZERS
// Called when a class instance is about to be deallocated
// BASIC DEINIT
class FileHandler {
var filename: String
init(filename: String) {
self.filename = filename
print("Opening file: \(filename)")
}
deinit {
print("Closing file: \(filename)")
// Clean up resources here
}
func read() -> String {
return "Contents of \(filename)"
}
}
// Demo deinit being called
func processFile() {
let handler = FileHandler(filename: "data.txt")
print(handler.read())
// handler goes out of scope here
} // deinit called automatically!
processFile()
// Output:
// Opening file: data.txt
// Contents of data.txt
// Closing file: data.txt
// DEINIT WITH CLEANUP
class DatabaseConnection {
var host: String
var isConnected: Bool = false
init(host: String) {
self.host = host
connect()
}
func connect() {
print("Connecting to \(host)...")
isConnected = true
print("Connected!")
}
func query(_ sql: String) {
guard isConnected else {
print("Not connected!")
return
}
print("Executing: \(sql)")
}
deinit {
if isConnected {
print("Disconnecting from \(host)...")
isConnected = false
print("Disconnected!")
}
}
}
// DEINIT IN INHERITANCE
class BaseResource {
var name: String
init(name: String) {
self.name = name
print("BaseResource \(name) allocated")
}
deinit {
print("BaseResource \(name) deallocated")
}
}
class FileResource: BaseResource {
var path: String
init(name: String, path: String) {
self.path = path
super.init(name: name)
print("FileResource \(path) allocated")
}
deinit {
print("FileResource \(path) deallocated")
// Superclass deinit called automatically after this!
}
}
func testInheritance() {
let file = FileResource(name: "Doc", path: "/tmp/doc.txt")
print("Using \(file.name)")
}
testInheritance()
// Output:
// BaseResource Doc allocated
// FileResource /tmp/doc.txt allocated
// Using Doc
// FileResource /tmp/doc.txt deallocated
// BaseResource Doc deallocated
// PRACTICAL EXAMPLE: TIMER CLEANUP
class GameTimer {
var timer: Timer?
var seconds: Int = 0
init() {
startTimer()
}
func startTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.seconds += 1
print("Seconds: \(self.seconds)")
}
}
deinit {
timer?.invalidate() // Clean up timer!
timer = nil
print("Timer cleaned up")
}
}
// NOTE: deinit is ONLY for classes
// Structs don't have deinit because they're value typesTry It Yourself!
Create a Logger class that opens a log file in init and closes it in deinit. Print messages when each occurs!