iOS/Swift

Swift 에서의 초기화와 초기화 해제 (init, deinit) 그리고 self

태애니 2025. 3. 19. 17:16
728x90

 

 

오늘 찾아본 키워드

1. 초기화
2. 초기화 해제
3. self

 

초기화 (Initialization)

 

 

초기화는 인스턴스를 만들 때 반드시 필요한 작업이다.

이를 수행하지 않으면 객체가 제대로 동작하지 않을 수 있다.

 

 

초기화가 필요한 이유는 다음과 같다.

  1. 프로퍼티에 올바른 초기값 설정
  2. 객체 생성 시 필요한 설정 수행
  3. 다양한 생성 방법 제공(initializer overloading)

 

// 1. 올바른 초기값 설정

class User {
    var name: String  // 초기값 없이 선언
    
    init(name: String) {
        self.name = name // 초기값을 설정하여 사용해야한다.
    }
}

let user1 = User(name: "Taenee")
let user2 = User() // Error!!

 

 

// 2. 객체 생성 시 필요한 설정 수행

class Sample {
    var sample: String

    init() {
        print("sample 값을 설정합니다.")
        self.sample = "default"
    }
}

let sample = Sample() // "sample 값을 설정합니다." 출력

 

 

// 3.다양한 생성 방법 제공(initializer overloading)

class UserInfo {
    var name: String
    var age: Int
    var job: String

    init(name: String, age: Int, job: String) {
        self.name = name
        self.age = age
        self.job = job
    }

    init(name: String, age: Int) {
        self.name = name
        self.age = age
        self.job = "탐색중👀" // 직업 없을 수도 있으니까
    }
}

let user1 = UserInfo(name: "Taeni", age: 31, job: "개발자")
let user2 = UserInfo(name: "Hong", age: 20)

 

 


 

 

초기화 해제(deinit)가 필요한 이유

초기화 해제는 메모리에서 객체가 제거될 때 실행되는 코드 블럭이다.

Swift의 ARC(Automatic Reference Counting)가 대부분의 메모리 관리를 자동으로 처리하지만, deinit 을 직접 수행하는 경우가 있다.

 

  1. 객체가 사라질 때 정리 하는 작업
  2. 메모리 누수 방지

 

// 1. 객체가 사라질 때 정리
// 네트워크 연결 해제, 파일 닫기, 리소스 정리 등의 작업을 수행할 때 직접 이 코드 블럭을 수행한다.

class FileHandler {
    var fileName: String

    init(fileName: String) {
        self.fileName = fileName
        print("\(fileName) 파일 초기화.")
    }

    deinit {
        print("\(fileName) 파일 초기화 해제.")
    }
}

var file: FileHandler? = FileHandler(fileName: "data.txt")
// "data.txt 파일 초기화." 출력

file = nil // "data.txt 파일 초기화 해제." 출력

 

 

// 2. 메모리 누수 방지
// 설명은 아래에 좀 더!!

import SwiftUI

class NetworkManager: ObservableObject {
    var networkTask: (() -> Void)?

    func setupTask() {
        networkTask = { [weak self] in
            print("\(self?.description ?? "self is nil")에서 네트워크 작업 실행")
        }
    }

    deinit {
        print("NetworkManager가 메모리에서 해제됨")
    }
}

struct ContentView: View {
    @StateObject private var networkManager = NetworkManager()

    var body: some View {
        VStack {
            Button("네트워크 작업 설정") {
                networkManager.setupTask()
            }
        }
    }
}

// 네트워크 작업을 설정한 후, ContentView가 사라지면 NetworkManager도 해제된다.

 

Swift 는 위에 말했듯이 ARC를 사용해 메모리를 자동으로 관리하지만, 강한 참조 순환이 발생하면 객체에 메모리가 계속 남아 Memory Leak 문제가 생기는 경우가 있다. 

 

예를 들어, 위의 코드에서 User 를 새로 인스턴스 화 해서 생성 후 이를 강한 참조로 갖게 된다면.

 

var user3: User? = User(name: “HarTaeni”)

var user4 = user3 // user4 는 user3의 객체를 바라보게 된다. (참조 카운트가 매겨진다.)

 

user3 = nil // 초기화 해제를 해도 user4의 참조 때문에 메모리에서 해제가 되지 않는다.

 

print(user4?.name) // “HarTaeni”

 

user4 = nil // 이렇게 설정해야 모두 해제 됨 -> 참조 카운트가 0이 되므로.

 

 

부분은 추후 자세히 다뤄보도록 예정🤔

 

결론적으로 [weak self]를 사용하여 강한 참조 순환을 방지한다고 생각하면 된다.

 

 

 


 

 

Self

현재 인스턴스를 가르키는 것으로,

같은 이름의 프로퍼티와 매개변수를 구분할 사용한다.

class Snack {
    var taste: String
    
    init(taste: String) {
        self.taste = taste // self를 사용하여 프로퍼티와 매개변수 구분
    }
    
    func printTaste() {
        print("이 과자는 \(self.taste) 맛 입니다.")
    }
}

 

728x90