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 디자인 패턴 강의와 예전 부트캠프를 통해 학습한 내용을 바탕으로 작성했습니다. 부족한 부분이나 잘못된 부분이 있다면 많이 알려주세요. 😭