싱글톤(Singleton) 패턴은 앱 전역에서 하나의 인스턴스를 공유하는 디자인 패턴입니다.
class로 구현하는 이유Swift에서 struct는 값 타입(Value Type)이고, class는 참조 타입(Reference Type)입니다. 싱글톤은 하나의 인스턴스를 유지하는 것이 핵심이므로, class를 사용해야 올바른 싱글톤이 됩니다.
class CoreDataManager {
static let shared = CoreDataManager() // 싱글톤 인스턴스
private init() { } // 외부에서 인스턴스 생성 방지
var data: [String] = []
}
// 사용 예시
CoreDataManager.shared.data.append("Hello")
print(CoreDataManager.shared.data) // ["Hello"]
struct CoreDataManager {
static var shared = CoreDataManager()
var data: [String] = []
}
// 새로운 인스턴스 생성 (값 복사)
var newManager = CoreDataManager.shared
newManager.data.append("World")
print(CoreDataManager.shared.data) // ["Hello"] (변경 안됨!)
print(newManager.data) // ["Hello", "World"]
구조체 기반 싱글톤은 shared를 복사할 때마다 새로운 인스턴스가 생기므로, 싱글톤의 의미가 사라집니다.
SwiftUI는 선언형 UI 프레임워크로, 데이터 흐름을 @StateObject, @EnvironmentObject, @Environment를 활용하여 관리할 수 있습니다.
즉, 싱글톤을 직접 사용하지 않아도 데이터를 전역으로 공유할 수 있습니다.
NSPersistentContainer를 SwiftUI에서 공유하는 방법import SwiftUI
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "MyModel")
container.loadPersistentStores { _, error in
if let error = error {
fatalError("Unresolved error \(error)")
}
}
}
}
위 코드는 struct로 싱글톤처럼 보이지만, 실제로 싱글톤 역할을 하는 것은 container(NSPersistentContainer)입니다.
@Environment를 활용한 CoreData 공유@main
struct MyApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
이렇게 하면 PersistenceController.shared를 직접 사용하지 않아도 @Environment(\.managedObjectContext)를 통해 데이터 공유가 가능합니다.
싱글톤 (Singleton) | @EnvironmentObject | |
|---|---|---|
| 데이터 저장 위치 | 앱 전역 인스턴스 | SwiftUI의 Environment |
| 라이프사이클 | 앱이 실행되는 동안 유지 | 뷰 계층이 유지되는 동안 유지 |
| 다중 인스턴스 가능 여부 | 불가능 (항상 하나) | 가능 (뷰마다 다를 수 있음) |
| 예제 | UserManager.shared | @EnvironmentObject var userManager: UserManager |
| 사용 방식 | UserManager.shared.username | userManager.username |
@EnvironmentObject의 사용 예시class UserManager: ObservableObject {
@Published var username: String = "Guest"
}
struct ContentView: View {
@EnvironmentObject var userManager: UserManager
var body: some View {
Text("Hello, \(userManager.username)!")
}
}
@main
struct MyApp: App {
@StateObject var userManager = UserManager()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(userManager)
}
}
}
@EnvironmentObject를 사용하면 싱글톤 없이도 데이터 공유가 가능하며, SwiftUI의 뷰 계층과 자연스럽게 연동됩니다.
@EnvironmentObject를 써야 할까?✅ 싱글톤을 사용해야 하는 경우
✅ @EnvironmentObject를 사용해야 하는 경우
SwiftUI에서 싱글톤을 완전히 배제할 필요는 없지만, 꼭 필요하지 않다면 @EnvironmentObject 같은 SwiftUI 전용 데이터 흐름을 활용하는 것이 좋습니다.
Core Data, API 클라이언트 같은 글로벌 데이터는 싱글톤이 적합하고, UI 상태나 유저 정보 같은 뷰 관련 데이터는 @EnvironmentObject가 더 적합합니다.
💡 즉, 사용 목적에 따라 적절한 방식을 선택하는 것이 중요합니다!