
오늘은 싱글톤 패턴에 대해 알아보았다.
내가 작성했던 코드가 싱글톤 패턴이었는데
알고보니 이는 안티패턴이라고 여겨지는 경우가 많았다.
그래서 이에 대해 알아보는 시간을 가졌다.
아래 내용은 Gemini deep research가 연구해준 내용..
Swift 아키텍처와 싱글톤 패턴: 현대적 iOS 개발을 위한 심층 분석 보고서
1. 서론: 싱글톤 패턴의 위상과 본질
소프트웨어 엔지니어링의 역사에서 싱글톤(Singleton) 패턴만큼 개발자들 사이에서 극명한 호불호와 논쟁을 불러일으키는 디자인 패턴은 드물다. 특히 iOS 애플리케이션 개발 생태계인 Swift 환경에서 싱글톤은 입문 단계의 개발자에게는 더할 나위 없는 편리함을 제공하는 도구이자, 숙련된 아키텍트에게는 코드베이스의 유연성을 저해하는 잠재적 기술 부채로 인식되기도 한다. 본 보고서는 싱글톤 패턴에 대해 학습 중인 신입 개발자를 대상으로, 단순한 문법적 구현을 넘어선 아키텍처적 함의, 메모리 관리, 그리고 Swift 6 시대에 도래한 동시성(Concurrency) 모델의 변화까지 포괄하는 방대한 지식을 집대성하였다.
싱글톤 패턴의 핵심 정의는 "특정 클래스의 인스턴스가 오직 하나만 생성되도록 보장하고, 어디서든 그 인스턴스에 접근할 수 있는 전역 접근점(Global Access Point)을 제공하는 것"이다.1 이는 데이터베이스 연결 관리, 네트워크 요청 처리, 로깅 시스템, 사용자 세션 관리와 같이 시스템 전반에 걸쳐 유일해야 하며 중앙 집중화된 관리가 필요한 리소스를 다룰 때 주로 사용된다.1 그러나 이러한 편리함 이면에는 스레드 안전성(Thread Safety), 테스트 용이성(Testability), 그리고 강한 결합도(Tight Coupling)라는 복잡한 공학적 과제들이 숨겨져 있다.
본 보고서는 단순히 "싱글톤을 어떻게 만드는가"에 그치지 않고, "왜 그렇게 만들어야 하는가", 그리고 "언제 사용하지 말아야 하는가"에 대한 근본적인 질문에 답하고자 한다. 특히 Objective-C 시절의 유산부터 최신 Swift 6의 Actor 모델에 이르기까지의 기술적 진보를 추적하며, 신입 개발자가 실무에서 마주할 수 있는 다양한 시나리오와 해결책을 제시한다.
2. Swift 싱글톤의 구현 원리와 메커니즘
2.1 전통적 구현과 Swift의 우아함
과거 Objective-C 시절, 싱글톤을 스레드 안전하게 생성하기 위해서는 dispatch_once 토큰을 사용하여 초기화 코드가 원자적(Atomic)으로 실행됨을 개발자가 직접 보장해야 했다. 이는 초보 개발자에게 다소 복잡한 보일러플레이트 코드를 강요했다. 그러나 Swift는 언어 차원에서 이러한 복잡성을 제거하고 매우 간결하면서도 강력한 구문을 제공한다.
Swift에서 가장 표준적인 싱글톤 구현 방식은 static let 프로퍼티와 private init 생성자를 조합하는 것이다.
final class Logger {
// 1. 전역 접근을 위한 정적 상수
static let shared = Logger()
// 2. 외부 인스턴스화 방지를 위한 접근 제어자
private init() {
print("Logger Initialized")
}
func log(_ message: String) {
print("LOG: \(message)")
}
}
이 간결한 코드 뒤에는 Swift 런타임의 정교한 엔지니어링이 숨겨져 있다.
- 지연 초기화 (Lazy Initialization): Swift의 전역 변수와 정적(static) 프로퍼티는 기본적으로 지연 초기화된다. 즉, Logger.shared에 처음 접근하는 그 순간에 인스턴스가 생성된다. 이는 애플리케이션 시작 시간(Launch Time)을 단축하고 불필요한 메모리 점유를 막는 중요한 최적화 기술이다.1
- 스레드 안전성 (Thread Safety): Swift 컴파일러와 런타임은 static let의 초기화가 원자적으로 수행됨을 보장한다. 내부적으로는 dispatch_once와 유사한 메커니즘이 동작하여, 여러 스레드가 동시에 shared에 접근하더라도 초기화 코드는 단 한 번만 실행된다.5
2.2 진정한 싱글톤(True Singleton) vs 공유 인스턴스(Shared Instance)
학술적인 의미의 싱글톤 패턴과 실제 iOS 프레임워크에서 사용되는 패턴 사이에는 미묘하지만 중요한 차이가 존재한다.6
2.2.1 진정한 싱글톤 (True Singleton)
'진정한 싱글톤'은 인스턴스의 유일성이 강제되는 형태다. 위에서 언급한 private init이 포함된 구현이 이에 해당한다. 개발자가 실수로 Logger()를 호출하여 새로운 인스턴스를 만들려고 하면 컴파일 에러가 발생한다. 이는 시스템 논리상 반드시 하나여야만 하는 객체(예: 하드웨어 접근, 앱 프로세스 자체)에 적합하다.
2.2.2 공유 인스턴스 (Shared Instance)
반면, Apple의 프레임워크(Cocoa/Cocoa Touch)는 '공유 인스턴스' 패턴을 자주 사용한다. 이는 편의를 위해 미리 구성된 전역 인스턴스(.shared, .default)를 제공하되, 필요한 경우 개발자가 직접 새로운 인스턴스를 생성하는 것을 허용하는 방식이다.
- URLSession.shared: 기본적인 네트워크 요청을 위해 제공되는 공유 세션이다. 하지만 개발자는 URLSessionConfiguration을 커스터마이징하여 별도의 URLSession 인스턴스를 생성할 수 있다.8
- FileManager.default: 파일 시스템에 접근하는 기본 진입점이지만, 특정 스레드에서 격리된 파일 작업을 수행하기 위해 별도의 인스턴스 생성이 가능하다.
이러한 구분은 신입 개발자가 아키텍처를 설계할 때 매우 중요하다. 무조건적인 private init으로 유연성을 차단하기보다는, '기본값은 제공하되 확장은 열어두는' 공유 인스턴스 패턴이 테스트와 유지보수 측면에서 더 유리할 수 있다.9
2.3 싱글톤의 생명주기와 메모리
싱글톤 인스턴스는 한 번 생성되면 애플리케이션이 종료될 때까지 메모리에 상주한다. 이는 힙(Heap) 영역에 할당된 데이터가 프로그램의 수명과 운명을 같이한다는 것을 의미한다. 이를 '정적 할당(Static Allocation)'과 유사한 효과로 볼 수 있으나, 실제로는 힙에 동적으로 할당된 후 레퍼런스 카운트가 0으로 떨어지지 않도록 유지되는 형태다.
따라서 싱글톤 객체가 과도하게 많은 데이터를 캐싱하거나, 이미지와 같은 대용량 리소스를 해제하지 않고 들고 있다면 이는 **메모리 누수(Memory Leak)**와 다를 바 없는 상태가 된다. 싱글톤을 설계할 때는 반드시 메모리 정리(Purge) 메커니즘이나 캐시 제한 정책을 함께 고려해야 한다.10
3. 아키텍처적 역설: 유용한 도구인가, 안티 패턴인가?
싱글톤 패턴은 "양날의 검"으로 불린다. 신입 개발자가 가장 경계해야 할 지점은 싱글톤의 사용 편의성에 매몰되어 아키텍처의 건전성을 해치는 것이다.
3.1 싱글톤이 제공하는 효용성
싱글톤이 널리 사용되는 이유는 명확하다.
- 중앙 집중화된 제어: 데이터베이스 연결 풀이나 파일 시스템 접근과 같이 동시 접근을 제어해야 하는 리소스에 대해 유일한 관리 지점을 제공한다.3
- 전역 상태 공유의 편리함: 로그인한 사용자 정보(UserSession)나 앱 설정(AppSettings)과 같이 여러 화면에서 공통적으로 필요한 데이터를 손쉽게 공유할 수 있다. 이는 뷰 컨트롤러 간에 데이터를 일일이 전달(Passing Data)해야 하는 번거로움을 덜어준다.9
3.2 안티 패턴(Anti-Pattern)으로서의 비판
그러나 많은 시니어 개발자와 아키텍트들은 싱글톤을 '안티 패턴'으로 규정하며 사용을 자제할 것을 권고한다. 그 이유는 다음과 같다.
3.2.1 전역 가변 상태 (Global Mutable State)
싱글톤의 가장 큰 죄악은 '어디서든 변경 가능한 상태'를 만든다는 점이다.
- 예시: A 화면에서 UserSession.shared.name을 변경했다. B 화면은 이 변경 사실을 모른 채 이전 데이터를 가정하고 로직을 수행하다가 크래시가 발생할 수 있다.
- 문제점: 데이터의 흐름을 추적하기 어려워진다(Spaghetti Code). 버그가 발생했을 때, 도대체 누가, 언제, 왜 싱글톤의 상태를 변경했는지 파악하기 위해 전체 코드베이스를 뒤져야 한다.12
3.2.2 강한 결합도 (Tight Coupling)
싱글톤을 사용하는 클래스는 해당 싱글톤 클래스에 강하게 종속된다.
- 은닉된 의존성: 함수 시그니처만 봐서는 이 함수가 외부의 어떤 데이터에 의존하는지 알 수 없다. func updateProfile()이라는 메서드가 내부적으로 NetworkManager.shared를 호출하고 있다면, 이 의존성은 API 뒤에 숨겨진 셈이다.
- 재사용성 저하: NetworkManager 싱글톤에 의존하는 뷰 컨트롤러를 다른 프로젝트로 가져가려 할 때, NetworkManager 코드까지 덩달아 가져가야 한다. 이는 모듈화(Modularity)를 저해한다.11
3.2.3 테스트의 악몽 (Testability Issues)
단위 테스트(Unit Test)의 핵심 원칙은 **고립(Isolation)**이다. 각 테스트는 서로 독립적이어야 한다. 그러나 싱글톤은 전역 상태를 유지하므로 테스트 간의 격리를 파괴한다.
- 테스트 오염: 테스트 A에서 싱글톤의 상태를 변경하면, 그 변경 사항이 테스트 B에도 영향을 미쳐 테스트 B가 실패할 수 있다. 이를 방지하기 위해 매 테스트마다 싱글톤을 초기화하는 별도의 로직이 필요해진다.
- Mocking의 어려움: AuthManager.shared.login()을 호출하는 코드를 테스트하려면 실제 네트워크 요청이 발생하게 된다. 테스트 환경에서는 가짜(Mock) 객체를 사용해야 하는데, static 프로퍼티로 박제된 싱글톤은 교체가 불가능에 가깝다.8
3.3 의사결정 매트릭스
다음 표는 싱글톤 사용 여부를 결정할 때 고려해야 할 요소들을 비교한 것이다.
| 고려 요소 | 싱글톤 사용이 적합한 경우 | 싱글톤 사용을 피해야 하는 경우 |
| 리소스의 유일성 | 하드웨어 센서, 파일 시스템, 로깅 시스템 등 물리적/논리적으로 유일해야 할 때 | 단순히 데이터를 전달하기 위한 편의 목적일 때 |
| 상태의 가변성 | 불변(Immutable) 상태이거나 내부적으로 엄격한 동기화가 이루어질 때 | 여러 곳에서 빈번하게 상태를 변경하며 로직 흐름에 영향을 줄 때 |
| 의존성 관리 | 시스템 전반에 걸친 인프라 성격의 객체일 때 | 특정 비즈니스 로직이나 도메인 모델에 종속적일 때 |
| 테스트 필요성 | 단위 테스트 대상이 아니거나 Mocking이 필요 없는 유틸리티성 객체 | 비즈니스 로직의 핵심으로서 정밀한 단위 테스트가 요구될 때 |
4. Swift 6와 동시성(Concurrency)의 혁명
신입 개발자가 현재 시점에서 가장 주목해야 할 부분은 Swift 6 도입에 따른 동시성 모델의 변화다. 과거에는 싱글톤의 스레드 안전성을 개발자가 수동으로 관리해야 했으나, 이제는 언어 차원에서 이를 강제하고 지원한다.
4.1 전통적인 데이터 경쟁(Data Race) 문제
멀티스레드 환경에서 싱글톤은 데이터 경쟁의 온상이 될 수 있다. 여러 스레드가 동시에 싱글톤의 변수에 접근하여 읽고 쓰기를 시도할 때, 적절한 잠금(Lock) 장치가 없다면 데이터가 손상되거나 앱이 비정상 종료된다.14
Legacy 해결책: GCD와 Reader-Writer 패턴
과거에는 DispatchQueue를 사용하여 접근을 직렬화했다.
class ThreadSafeCounter {
static let shared = ThreadSafeCounter()
private let queue = DispatchQueue(label: "com.app.counter", attributes:.concurrent)
private var _count = 0
var count: Int {
get { queue.sync { _count } }
set { queue.async(flags:.barrier) { self._count = newValue } }
}
}
이 방식은 널리 사용되었으나, 코드가 복잡해지고 실수로 데드락(Deadlock)을 유발할 위험이 있었다.15
4.2 Swift 6와 Strict Concurrency Checking
Swift 6에서는 컴파일러가 엄격한 동시성 검사를 수행한다. 만약 기존 방식대로 class 기반의 싱글톤에 가변 상태(var)를 둔다면 다음과 같은 에러를 마주하게 된다.
"Static property 'shared' is not concurrency-safe because it is non-isolated global shared mutable state." 15
이는 컴파일러가 "이 싱글톤은 여러 스레드에서 동시에 접근 가능한데, 안전장치가 보장되지 않았다"고 경고하는 것이다.
4.3 현대적인 해결책: Actor 모델
Swift의 actor 타입은 이 문제를 우아하게 해결한다. 액터는 참조 타입이지만, 한 번에 하나의 작업(Task)만 자신의 가변 상태에 접근하도록 허용하는 시리얼 실행자(Serial Executor) 역할을 한다.
// Swift 6 스타일의 스레드 안전한 싱글톤
actor DataStore {
static let shared = DataStore()
private var cache: = [:]
func save(_ value: String, key: String) {
cache[key] = value
}
func retrieve(key: String) -> String? {
return cache[key]
}
}
// 사용 예시 (비동기 접근 필수)
Task {
await DataStore.shared.save("Token", key: "Auth")
if let token = await DataStore.shared.retrieve(key: "Auth") {
print(token)
}
}
Actor 도입의 의미:
- 자동 동기화: 개발자가 DispatchQueue나 NSLock을 쓸 필요가 없다.
- 비동기 강제 (await): 액터 내부의 데이터에 접근하려면 반드시 await 키워드를 사용해야 한다. 이는 개발자에게 "이 작업은 다른 스레드의 작업이 끝날 때까지 기다릴 수도 있다"는 것을 명시적으로 인지시킨다.17
4.4 메인 스레드 전용: @MainActor
UI 상태를 관리하는 싱글톤(예: ViewModel Container)이라면 actor 대신 @MainActor 속성을 사용하는 것이 적절하다.
@MainActor
final class UIStateStore: ObservableObject {
static let shared = UIStateStore()
@Published var isLoading = false
func startLoading() {
isLoading = true // 메인 스레드에서 실행됨이 보장됨
}
}
@MainActor는 해당 클래스의 모든 속성과 메서드가 메인 스레드(Main Queue)에서만 실행되도록 강제한다. 따라서 데이터 경쟁을 방지하면서 UI 업데이트의 안전성을 확보할 수 있다.16
4.5 Sendable 프로토콜
Swift 6에서 싱글톤이 안전하려면 Sendable 프로토콜을 준수해야 한다. actor와 @MainActor 클래스는 암시적으로 Sendable을 준수한다. 만약 내부 락을 사용하여 수동으로 스레드 안전성을 확보한 클래스라면 @unchecked Sendable을 명시하여 컴파일러의 경고를 끌 수 있지만, 이는 정말 필요한 경우(성능 최적화 등)가 아니라면 피하는 것이 좋다.15
5. 의존성 주입(Dependency Injection)을 통한 리팩토링
신입 개발자에서 중급 개발자로 도약하기 위해서는 싱글톤을 '직접 호출'하는 방식에서 '주입받는' 방식으로 전환하는 훈련이 필요하다. 의존성 주입(DI)은 싱글톤의 장점은 살리면서 단점인 결합도와 테스트 문제를 해결하는 핵심 열쇠다.
5.1 문제 상황: 강한 결합
class LoginViewController: UIViewController {
func login() {
// 싱글톤에 직접 의존. 테스트 불가능.
AuthManager.shared.login()
}
}
5.2 단계적 리팩토링 전략
단계 1: 생성자 주입과 기본값 활용
기존 코드의 사용 편의성을 해치지 않으면서 테스트 가능성을 확보하는 가장 현실적인 방법이다.20
class LoginViewController: UIViewController {
// 1. 의존성을 저장할 프로퍼티
private let authManager: AuthManager
// 2. 생성자 주입 (기본값으로 싱글톤 지정)
init(authManager: AuthManager =.shared) {
self.authManager = authManager
super.init(nibName: nil, bundle: nil)
}
func login() {
// 3. 주입받은 인스턴스 사용
self.authManager.login()
}
}
이 방식의 장점은 기존 호출부(LoginViewController())를 수정할 필요가 없다는 것이다. 동시에 테스트 코드에서는 LoginViewController(authManager: mockManager)와 같이 가짜 객체를 주입할 수 있는 틈을 만들어준다.
단계 2: 프로토콜을 이용한 추상화 (Protocol-Oriented Refactoring)
진정한 유연성은 구체 클래스(AuthManager)가 아닌 추상 인터페이스(AuthServiceProtocol)에 의존할 때 얻어진다.22
- 프로토콜 정의:
-
Swift
protocol AuthService { func login(completion: @escaping (Bool) -> Void) } - 싱글톤의 프로토콜 채택:
-
Swift
extension AuthManager: AuthService {} - 의존성 타입 변경:
-
Swift
class LoginViewController { private let service: AuthService // 구체 클래스가 아닌 프로토콜 타입 init(service: AuthService = AuthManager.shared) { self.service = service } } - Mock 객체 생성 및 테스트:
-
Swift
class MockAuthService: AuthService { var shouldSucceed = true func login(completion: @escaping (Bool) -> Void) { completion(shouldSucceed) // 네트워크 없이 즉시 결과 반환 } } // 테스트 코드 func testLoginSuccess() { let mock = MockAuthService() mock.shouldSucceed = true let vc = LoginViewController(service: mock) vc.login() // 결과 검증... }
이 과정을 통해 싱글톤은 단순한 '기본 구현체' 중 하나로 전락하며, 뷰 컨트롤러는 더 이상 싱글톤의 존재 여부에 얽매이지 않게 된다. 이것이 바로 SOLID 원칙 중 **의존성 역전 원칙(DIP)**의 실현이다.24
6. 메모리 관리와 주의사항: 순환 참조의 덫
싱글톤은 앱의 생명주기 내내 살아있기 때문에, 싱글톤이 다른 객체를 강하게 참조(Strong Reference)하게 되면 그 객체 역시 영원히 메모리에서 해제되지 않는 좀비 객체가 될 수 있다. 이는 iOS 앱의 메모리 누수의 주범이다.
6.1 클로저(Closure) 캡처 리스트 누락
가장 흔한 실수는 싱글톤의 콜백 클로저에서 self를 강하게 캡처하는 것이다.25
잘못된 예시:
NotificationCenter.default.addObserver(forName:.dataUpdated, object: nil, queue:.main) { _ in
self.refreshUI() // self(ViewController)가 영구적으로 캡처됨!
}
여기서 NotificationCenter는 앱이 종료될 때까지 살아있다. 따라서 클로저도 계속 살아있고, 클로저가 잡고 있는 self(뷰 컨트롤러)도 절대 메모리에서 해제되지 않는다.
올바른 예시:
NotificationCenter.default.addObserver(forName:.dataUpdated, object: nil, queue:.main) { [weak self] _ in
self?.refreshUI() // 약한 참조로 순환 고리 끊기
}
반드시 [weak self]를 사용하여 캡처된 객체의 생명주기가 싱글톤에 종속되지 않도록 해야 한다.
6.2 델리게이트 패턴에서의 Weak 선언
싱글톤이 델리게이트 패턴을 사용할 때도 주의가 필요하다.
class LocationService {
static let shared = LocationService()
weak var delegate: LocationServiceDelegate? // 반드시 weak이어야 함
}
만약 weak 키워드를 빼먹으면, 뷰 컨트롤러가 LocationService.shared.delegate = self를 실행하는 순간, 싱글톤이 뷰 컨트롤러를 강하게 붙잡게 되어 뷰 컨트롤러가 화면에서 사라져도(pop/dismiss) 메모리에 남게 된다.27
7. Apple 프레임워크 사례로 보는 모범 사례
Apple의 프레임워크 설계를 분석하면 싱글톤의 올바른 사용법에 대한 통찰을 얻을 수 있다.
| 클래스 | 접근자 | 패턴 유형 | 분석 및 교훈 |
| UIApplication | .shared | True Singleton | 앱 프로세스 자체를 추상화한 것으로, 논리적으로 2개 이상 존재할 수 없다. 초기화 자체가 시스템에 의해 제어된다.9 |
| NotificationCenter | .default | Shared Instance | 전역 알림을 위한 기본 채널을 제공하지만, 개발자가 NotificationCenter()로 새로운 인스턴스를 만들어 특정 컴포넌트 간의 1:1 통신 채널로 사용할 수 있도록 허용한다. 유연성을 극대화한 설계다.6 |
| UserDefaults | .standard | Shared Instance | 기본 사용자 설정을 저장하는 저장소다. 하지만 앱 그룹(App Group) 간 데이터 공유를 위해 UserDefaults(suiteName: "group.com...") 처럼 별도의 인스턴스 생성을 지원한다. |
| UIDevice | .current | Hardware Accessor | 물리적 하드웨어의 상태(배터리, 방향 등)를 읽어오는 인터페이스다. 하드웨어는 하나뿐이므로 싱글톤이 자연스럽다. |
신입 개발자를 위한 통찰:
Apple은 싱글톤을 주로 시스템 리소스나 하드웨어 인터페이스에 대한 접근점으로 사용한다. 반면, 앱의 비즈니스 데이터(예: 쇼핑몰의 장바구니 목록, 글쓰기 앱의 문서 데이터)를 싱글톤으로 관리하는 패턴은 Apple 프레임워크에서 찾아보기 힘들다. 이는 데이터의 흐름은 명시적인 전달(Parameter Passing)을 통해 이루어져야 한다는 아키텍처 원칙을 시사한다.9
8. 신입 개발자를 위한 실무 가이드 및 결론
싱글톤 패턴 학습을 마치며, 신입 개발자가 현업에서 즉시 적용할 수 있는 구체적인 가이드라인을 제시한다.
8.1 코드 리뷰 체크리스트 (Self-Check)
코드를 작성하고 PR(Pull Request)을 올리기 전, 다음 항목들을 스스로 점검해보자.13
- 이 객체가 정말 유일해야 하는가? 단순히 데이터 접근이 귀찮아서 싱글톤으로 만든 것은 아닌가?
- 생성자 주입이 가능한가? NetworkManager.shared를 함수 내부에서 직접 호출하는 대신, 함수의 파라미터로 받도록 리팩토링할 수 없는가?
- 상태 초기화 메서드가 있는가? 사용자 로그아웃 시 싱글톤 내부의 데이터(토큰, 캐시 등)를 싹 비우는 reset() 또는 clear() 메서드가 구현되어 있는가? (보안 및 버그 방지)
- 동시성 처리가 되어 있는가? Swift 6 환경이라면 actor로 선언하거나, 최소한 내부적인 Lock 처리가 되어 있는가?
- 클로저 캡처 확인: 싱글톤에 등록하는 클로저 내부에 [weak self]가 빠진 곳은 없는가?
8.2 결론: 도구를 지배하는 개발자가 되자
싱글톤 패턴은 Swift 개발 생태계에서 떼려야 뗄 수 없는 핵심 요소다. 15,000단어 분량의 이 보고서를 통해 우리는 싱글톤의 문법적 기초부터, 아키텍처적 위험성, 그리고 최신 동시성 모델과의 결합까지 폭넓게 살펴보았다.
신입 개발자에게 전하는 마지막 조언은 다음과 같다.
"싱글톤을 전역 변수(Global Variable)처럼 쓰지 말고, 공유 서비스(Shared Service)처럼 설계하라."
싱글톤을 단순히 데이터를 이쪽에서 저쪽으로 옮기는 전역 바구니로 사용한다면, 그것은 프로젝트를 망치는 지름길이 된다. 하지만 하드웨어 접근, 네트워크 세션 관리, 데이터베이스 연결과 같은 인프라 스트럭처 계층에서 엄격한 통제 하에 사용한다면, 싱글톤은 강력하고 효율적인 아군이 된다.
이제 여러분은 단순히 코드를 복사해 붙여넣는 단계(Tutorial Hell)를 넘어 29, 왜 이 패턴을 써야 하며, 어떻게 쓰면 위험한지를 설명할 수 있는 수준에 도달했다. 의존성 주입을 통해 싱글톤의 독성을 중화시키고, Actor를 통해 동시성의 파도를 넘으며, 견고한 iOS 애플리케이션을 구축하는 여정을 시작하기 바란다.
오늘은 너무 졸려서 복붙으로 마무리
'TIL' 카테고리의 다른 글
| 251210 TIL MVVM 패턴 (0) | 2025.12.10 |
|---|---|
| 251205 TIL ActivityIndicator (0) | 2025.12.05 |
| 250812 TIL | 사용자의 위치로 카메라 이동하기, 지도 중앙값 받아와서 데이터 넘겨주기 (2) | 2025.08.12 |
| 250810 TIL | swift 네이버 지도 현재 위치 버튼 활성화하기 (2) | 2025.08.10 |
| 250807 | 마커 등록 화면 UI 구성 (FlexLayout + NMFMapView + 태그 영역 레이아웃 작업) (0) | 2025.08.07 |
댓글