Swift를 사용하다 보면 특정 객체들이 Singleton 패턴을 이용해 구현된 걸 확인할 수 있다.
예를 들어 UIApplication 같은 경우 공식 문서를 보면 iOS 앱은 하나의 UIApplication 인스턴스를 가지고 있다고 나와있다.
Thread safe란? 멀티 스레드 환경에서 어떤 함수나 객체가 여러 스레드에 의해 동시에 접근 되더라도 문제없이 각 스레드에서 원하는 결과가 도출 된다는 것을 의미한다.
여러 스레드에서 싱글톤 객체에 접근할 때 해당 객체가 유일한 객체인지 보장할 수 있는지에 대해 고민해 봐야 한다.
1. 미리 인스턴스화해서 사용한다.
2. 중첩 타입을 활용한다?
Java에서는 중첩 타입을 이용해 thread-safe 한 Singleton 객체를 만든다고 한다.
class DefaultSetting {
private init() { }
private class DefaultSettingHolder {
static let shared = DefaultSetting()
}
static func shared() -> DefaultSettingHolder {
return DefaultSettingHolder.shared
}
}
// Java를 잘 몰라 Swift로 비슷하게 구현(참고만 하세요.)
타입(static) 변수를 통해 thread-safe 한 Singleton 객체를 구현할 수 있지만 Java같은 경우 타입 변수로 해당 Singleton 객체를 생성하면 해당 객체를 당장 사용하지 않더라도 메모리에 할당되기 때문에 메모리 낭비가 발생해 위 코드처럼 작성하는 방법이 존재하는 걸로 알고 있다.
Swift에서도 타입 프로퍼티를 이용해 Singleton 객체를 구현하는 데 그렇다면 여기서도 메모리 낭비가 발생하는 게 아닌가라는 고민을 할 수 있다.
Apple blog를 보면 해답을 찾을 수 있다.
The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic.
전역 변수에 대한 초기화는 최초 접근할 때 초기화된다고 한다.
class DefaultSetting {
static let shared = DefaultSetting()
private init() { }
func doSomething() {
....
}
}
타입 프로퍼티를 활용해 전역에서 접근할 수 있는 객체를 생성해 하나의 인스턴스라는 것을 보장하고 private init을 통해 더이상 인스턴스를 생성하지 못하도록 코드를 작성해야 한다.
해당 글은 인프런의 코딩으로 학습하는 GoF 디자인 패턴 강의와 예전 부트캠프를 통해 학습한 내용을 바탕으로 작성했습니다. 부족한 부분이나 잘못된 부분이 있다면 많이 알려주세요. 😭