Conversation
📝 WalkthroughWalkthroughThis PR establishes a layered dependency injection system using a multi-assembler pattern (Data → Domain → Presentation), initializes the DI container at app startup, replaces placeholder views with a complete test feature demonstrating the DI flow, and removes legacy placeholder files. Changes
Sequence DiagramsequenceDiagram
participant App as App Launch
participant DI as DIContainer
participant DataAsm as Data Assembler
participant DomainAsm as Domain Assembler
participant PresentationAsm as Presentation Assembler
participant Factory as ViewFactory
participant VM as TestViewModel
App->>DI: init() calls dependencyInjection()
rect rgb(200, 220, 255)
Note over DataAsm,PresentationAsm: DI Initialization Chain
DI->>DataAsm: create & assemble()
DataAsm->>DI: register TestInterface → DefaultTestRepository
DI->>DomainAsm: create with DataAsm as preAssembler & assemble()
DomainAsm->>DataAsm: assemble()
DataAsm->>DI: (re-register data dependencies)
DomainAsm->>DI: resolve TestInterface
DI-->>DomainAsm: DefaultTestRepository
DomainAsm->>DI: register TestUseCase → DefaultTestUseCase
DI->>PresentationAsm: create with DomainAsm as preAssembler & assemble()
PresentationAsm->>DomainAsm: assemble()
DomainAsm->>DI: (re-assemble domain dependencies)
PresentationAsm->>DI: resolve TestUseCase
DI-->>PresentationAsm: DefaultTestUseCase
PresentationAsm->>DI: register TestViewModel with TestUseCase
end
rect rgb(220, 240, 220)
Note over Factory,VM: View Creation
App->>Factory: makeTestView()
Factory->>DI: resolve TestViewModel
DI-->>Factory: TestViewModel instance
Factory-->>App: TestView with bound ViewModel
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Fix all issues with AI Agents 🤖
In @Cherrish-iOS/Cherrish-iOS/App/DIContainer+.swift:
- Line 2: The file header comment currently says "AppDIContainer+.swift" but the
actual file is named "DIContainer+.swift"; update the top-of-file header comment
to match the real filename by replacing "AppDIContainer+.swift" with
"DIContainer+.swift" (or conversely rename the file if the header is
authoritative), ensuring the header and actual filename are consistent.
In @Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift:
- Around line 20-25: The dependencies dictionary is not thread-safe: mutations
in register(type:closure:) and reads in resolve can race; protect access to the
private dependencies by adding a synchronization primitive (e.g., a private
serial DispatchQueue or an NSLock) and wrap all reads and writes to dependencies
with that lock/queue (use sync for reads and async/sync or barrier for writes if
using a concurrent queue). Update register(type:closure:) and resolve to use
this synchronization so all accesses to dependencies are serialized and data
races are prevented.
In @Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestView.swift:
- Around line 1-2: Update the file header comment to match the actual filename
by replacing the incorrect "ContentView.swift" text with "TestView.swift" in the
top-of-file comment; ensure any other header metadata (if present) also reflects
TestView.swift so the header is consistent with the file and class/struct names
in TestView.
In
@Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift:
- Around line 17-27: In assemble(), remove the debug print statement inside the
DIContainer.shared.register closure (the line that prints "뷰모델 등록"); instead
either delete it or replace it with a call to the app logging facility (e.g.,
Logger.log or similar) if persistent logs are required; ensure the closure still
returns TestViewModel(testUseCase: testUseCase) and keep the guard resolving
TestUseCase unchanged.
In @Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift:
- Around line 15-21: Replace the fatalError in makeTestView: when
DIContainer.shared.resolve(type: TestViewModel.self) returns nil, log the
failure (using the app logger or print), and return a safe fallback TestView
instance instead of crashing; implement this by either creating a lightweight
DefaultTestViewModel (or a TestViewModel.mock()/initWithDefaults()) and
returning TestView(viewModel: defaultVM), or add a TestView.init() convenience
initializer that creates an empty/placeholder UI and return that; update
makeTestView to use the fallback path and keep the method signature unchanged so
callers aren’t forced to handle throws.
🧹 Nitpick comments (8)
Cherrish-iOS/Cherrish-iOS/Domain/Interface/TestInterface.swift (1)
10-12: Consider adding explicit access control modifier.The protocol serves as a public contract between Domain and Data layers. While Swift defaults to internal access, explicitly declaring
internal protocol TestInterface(orpublicif cross-module usage is intended) improves code clarity and makes architectural boundaries more visible.🔎 Proposed fix
-protocol TestInterface { +internal protocol TestInterface { func test() }Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestView.swift (1)
10-22: LGTM! View correctly integrates with ViewModel via dependency injection.The SwiftUI view properly uses
@ObservedObjectto observe the externally-injected ViewModel, and the Button action correctly triggers the ViewModel's test method while displaying reactive state.Minor: Simplify string interpolation
Line 18 uses unnecessary string interpolation.
Textcan accept aStringdirectly:- Text("\(viewModel.text)") + Text(viewModel.text)Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift (1)
30-31: Remove trailing empty lines.Clean up the unnecessary empty lines at the end of the file.
🔎 Proposed fix
} } - -Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift (2)
10-12: Consider whether the protocol is necessary.The protocol
ViewFactoryProtocolis only implemented byViewFactory. Unless you plan to have multiple implementations or need to mock this for testing, the protocol might be unnecessary overhead.
17-17: Address the TODO comment.The TODO indicates missing fallback handling when DI resolution fails. This should be resolved before merging to ensure robust error handling.
Do you want me to open a new issue to track implementing the fallback behavior, or would you prefer to address it in this PR?
Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift (1)
22-25: Consider adding lifecycle management for different dependency scopes.The current implementation always creates new instances on each
resolve()call. Consider supporting different lifecycles:
- Transient: New instance each time (current behavior)
- Singleton: Single shared instance created once
- Scoped: Instance per scope (e.g., per request/session)
This would provide more flexibility for production use beyond test scenarios.
Cherrish-iOS/Cherrish-iOS/Domain/UseCase/TestUseCase.swift (2)
2-2: Update file header to match actual filename.The header comment references "Usecase.swift" but the actual filename is "TestUseCase.swift". Update for consistency.
🔎 Proposed fix
// -// Usecase.swift +// TestUseCase.swift // Cherrish-iOS
21-24: Consider replacing debug print with proper logging.The
🔎 Example using OSLog (if targeting iOS 14+)
import os.log private let logger = Logger(subsystem: "com.cherrish", category: "UseCase") func execute() { self.repository.test() logger.debug("UseCase execute") }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
Cherrish-iOS/Cherrish-iOS/App/Cherrish_iOSApp.swiftCherrish-iOS/Cherrish-iOS/App/DIContainer+.swiftCherrish-iOS/Cherrish-iOS/Core/DIContainer.swiftCherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swiftCherrish-iOS/Cherrish-iOS/Data/Repository/Repository.swiftCherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swiftCherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swiftCherrish-iOS/Cherrish-iOS/Domain/Interface/TestInterface.swiftCherrish-iOS/Cherrish-iOS/Domain/UseCase/TestUseCase.swiftCherrish-iOS/Cherrish-iOS/Domain/UseCase/Usecase.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/ContentView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/TestView.swiftCherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swiftCherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swiftCherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift
💤 Files with no reviewable changes (3)
- Cherrish-iOS/Cherrish-iOS/Data/Repository/Repository.swift
- Cherrish-iOS/Cherrish-iOS/Presentation/Feature/ContentView.swift
- Cherrish-iOS/Cherrish-iOS/Domain/UseCase/Usecase.swift
🧰 Additional context used
🧬 Code graph analysis (10)
Cherrish-iOS/Cherrish-iOS/Domain/Interface/TestInterface.swift (2)
Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift (1)
test(11-13)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swift (1)
test(18-22)
Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift (2)
Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift (1)
assemble(17-27)Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift (1)
assemble(17-28)
Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift (3)
Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift (1)
assemble(11-15)Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift (1)
assemble(17-28)Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift (2)
resolve(27-34)register(22-25)
Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift (3)
Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift (1)
assemble(11-15)Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift (1)
assemble(17-27)Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift (2)
resolve(27-34)register(22-25)
Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift (1)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swift (1)
test(18-22)
Cherrish-iOS/Cherrish-iOS/App/Cherrish_iOSApp.swift (2)
Cherrish-iOS/Cherrish-iOS/App/DIContainer+.swift (1)
dependencyInjection(11-17)Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift (1)
makeTestView(15-21)
Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift (1)
Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift (1)
resolve(27-34)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swift (2)
Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift (1)
test(11-13)Cherrish-iOS/Cherrish-iOS/Domain/UseCase/TestUseCase.swift (1)
execute(21-24)
Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestView.swift (2)
Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift (1)
test(11-13)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swift (1)
test(18-22)
Cherrish-iOS/Cherrish-iOS/Domain/UseCase/TestUseCase.swift (2)
Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift (1)
test(11-13)Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swift (1)
test(18-22)
🪛 SwiftLint (0.57.0)
Cherrish-iOS/Cherrish-iOS/App/Cherrish_iOSApp.swift
[Warning] 14-14: TODOs should be resolved (코디네이터에서 실행하기)
(todo)
Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift
[Warning] 17-17: TODOs should be resolved (DI 실패 시 기본으로 갈 곳 지정)
(todo)
🔇 Additional comments (14)
Cherrish-iOS/Cherrish-iOS/App/Cherrish_iOSApp.swift (2)
13-16: LGTM! DI initialization at app startup is appropriate.The initialization pattern correctly wires up all dependency layers before the view hierarchy is constructed. The TODO comment appropriately flags the planned migration to a coordinator pattern.
20-20: LGTM! ViewFactory pattern correctly decouples view construction.Using
ViewFactory.makeTestView()properly delegates view construction to the factory, which handles ViewModel resolution from DIContainer. This maintains separation of concerns.Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestViewModel.swift (2)
10-16: LGTM! ViewModel correctly implements dependency injection and SwiftUI state management.The
final classprevents unnecessary subclassing,@Publishedproperly exposes state to SwiftUI, and constructor-based dependency injection cleanly decouples the ViewModel from concrete UseCase implementations.
18-22: LGTM! State update logic correctly follows the use case execution.The method appropriately delegates business logic to the use case, then updates UI state. The console logging aids debugging during this test/demo phase.
Cherrish-iOS/Cherrish-iOS/Data/Repository/TestRepository.swift (1)
10-14: LGTM! Repository implementation correctly conforms to the domain interface.Using a
structis appropriate for this stateless repository. The implementation correctly fulfills theTestInterfacecontract and demonstrates the Data layer in the DI flow.Cherrish-iOS/Cherrish-iOS/App/DIContainer+.swift (1)
10-17: LGTM! Assembler chain pattern is well-structured.The dependency injection setup correctly chains the assemblers in the proper layer order (Data → Domain → Presentation), allowing each layer to resolve dependencies from the previous layer.
Cherrish-iOS/Cherrish-iOS/Data/DataDependencyAssembler.swift (1)
10-15: LGTM! Data layer registration is correct.The assembler correctly registers the concrete repository implementation for the data layer interface. As the first assembler in the chain, it appropriately has no preAssembler dependency.
Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift (1)
10-15: LGTM! Assembler structure follows the established pattern.The preAssembler dependency and initialization correctly implement the chain-of-responsibility pattern for multi-layer DI wiring.
Cherrish-iOS/Cherrish-iOS/Domain/DomainDependencyAssembler.swift (1)
10-27: LGTM! Domain layer assembler correctly implements the pattern.The assembler properly chains with the data layer assembler, resolves the repository interface, and registers the use case. The guard statement ensures safe handling when dependencies are unavailable.
Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift (3)
10-12: LGTM! Clean protocol definition.The
DependencyAssemblerprotocol provides a clear contract for dependency assembly across layers.
14-18: LGTM! Singleton pattern correctly implemented.The
finalmodifier and private initializer properly enforce singleton access.
27-34: LGTM! Safe optional resolution logic.The method correctly returns
nilwhen a dependency isn't registered, and the safe cast (as? T) prevents runtime crashes if type mismatches occur.Cherrish-iOS/Cherrish-iOS/Domain/UseCase/TestUseCase.swift (2)
10-12: LGTM! Clean protocol abstraction.The protocol provides a simple, clear contract for use case execution.
14-19: LGTM! Appropriate use of value semantics.Using a
structwith an immutablerepositorydependency is a good Swift practice for use cases without shared mutable state.
| @@ -0,0 +1,18 @@ | |||
| // | |||
| // AppDIContainer+.swift | |||
There was a problem hiding this comment.
File name mismatch in header comment.
The header comment references "AppDIContainer+.swift" but the actual filename is "DIContainer+.swift".
🔎 Proposed fix
-// AppDIContainer+.swift
+// DIContainer+.swift📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // AppDIContainer+.swift | |
| // DIContainer+.swift |
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/App/DIContainer+.swift around line 2, The file
header comment currently says "AppDIContainer+.swift" but the actual file is
named "DIContainer+.swift"; update the top-of-file header comment to match the
real filename by replacing "AppDIContainer+.swift" with "DIContainer+.swift" (or
conversely rename the file if the header is authoritative), ensuring the header
and actual filename are consistent.
| private var dependencies: [String: () -> Any] = [:] | ||
|
|
||
| func register<T>(type: T.Type, closure: @escaping () -> T) { | ||
| let key = String(describing: T.self) | ||
| dependencies[key] = closure | ||
| } |
There was a problem hiding this comment.
Add thread-safety to prevent data races.
The dependencies dictionary is mutated in register and accessed in resolve without any synchronization. If multiple threads call these methods concurrently (e.g., during app initialization with async tasks, or from background threads), this can lead to data races and crashes.
🔎 Proposed fix using a serial queue or lock
final class DIContainer {
static let shared = DIContainer()
private init() { }
+ private let queue = DispatchQueue(label: "com.cherrish.dicontainer", attributes: .concurrent)
private var dependencies: [String: () -> Any] = [:]
func register<T>(type: T.Type, closure: @escaping () -> T) {
let key = String(describing: T.self)
- dependencies[key] = closure
+ queue.async(flags: .barrier) { [weak self] in
+ self?.dependencies[key] = closure
+ }
}
func resolve<T>(type: T.Type) -> T? {
let key = String(describing: T.self)
- guard let closure = dependencies[key] else {
- return nil
- }
-
- return closure() as? T
+ return queue.sync {
+ guard let closure = dependencies[key] else {
+ return nil
+ }
+ return closure() as? T
+ }
}
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Core/DIContainer.swift around lines 20-25, The
dependencies dictionary is not thread-safe: mutations in register(type:closure:)
and reads in resolve can race; protect access to the private dependencies by
adding a synchronization primitive (e.g., a private serial DispatchQueue or an
NSLock) and wrap all reads and writes to dependencies with that lock/queue (use
sync for reads and async/sync or barrier for writes if using a concurrent
queue). Update register(type:closure:) and resolve to use this synchronization
so all accesses to dependencies are serialized and data races are prevented.
| // | ||
| // ContentView.swift |
There was a problem hiding this comment.
Fix the file header comment mismatch.
The header comment references "ContentView.swift" but the actual file is "TestView.swift". This inconsistency can cause confusion during code navigation and maintenance.
🔎 Proposed fix
//
-// ContentView.swift
+// TestView.swift
// Cherrish-iOS📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // | |
| // ContentView.swift | |
| // | |
| // TestView.swift |
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/Feature/TestView.swift around lines
1-2, Update the file header comment to match the actual filename by replacing
the incorrect "ContentView.swift" text with "TestView.swift" in the top-of-file
comment; ensure any other header metadata (if present) also reflects
TestView.swift so the header is consistent with the file and class/struct names
in TestView.
| func assemble() { | ||
| preAssembler.assemble() | ||
|
|
||
| guard let testUseCase = DIContainer.shared.resolve(type: TestUseCase.self) else { | ||
| return | ||
| } | ||
|
|
||
| DIContainer.shared.register(type: TestViewModel.self) { | ||
| print("뷰모델 등록") | ||
| return TestViewModel(testUseCase: testUseCase) | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Remove debug print statement before production.
The print statement on line 25 should be removed or replaced with proper logging infrastructure. Debug prints are not suitable for production code.
🔎 Proposed fix
DIContainer.shared.register(type: TestViewModel.self) {
- print("뷰모델 등록")
return TestViewModel(testUseCase: testUseCase)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func assemble() { | |
| preAssembler.assemble() | |
| guard let testUseCase = DIContainer.shared.resolve(type: TestUseCase.self) else { | |
| return | |
| } | |
| DIContainer.shared.register(type: TestViewModel.self) { | |
| print("뷰모델 등록") | |
| return TestViewModel(testUseCase: testUseCase) | |
| } | |
| func assemble() { | |
| preAssembler.assemble() | |
| guard let testUseCase = DIContainer.shared.resolve(type: TestUseCase.self) else { | |
| return | |
| } | |
| DIContainer.shared.register(type: TestViewModel.self) { | |
| return TestViewModel(testUseCase: testUseCase) | |
| } |
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/PresentationDependencyAssembler.swift
around lines 17-27, In assemble(), remove the debug print statement inside the
DIContainer.shared.register closure (the line that prints "뷰모델 등록"); instead
either delete it or replace it with a call to the app logging facility (e.g.,
Logger.log or similar) if persistent logs are required; ensure the closure still
returns TestViewModel(testUseCase: testUseCase) and keep the guard resolving
TestUseCase unchanged.
| static func makeTestView() -> TestView { | ||
| guard let viewModel = DIContainer.shared.resolve(type: TestViewModel.self) else { | ||
| // TODO: DI 실패 시 기본으로 갈 곳 지정 | ||
| fatalError() | ||
| } | ||
| return TestView(viewModel: viewModel) | ||
| } |
There was a problem hiding this comment.
Replace fatalError with graceful degradation.
Using fatalError() when DI resolution fails will crash the app. Since this factory is called during app initialization, a crash here provides a poor user experience. Consider:
- Logging the error for debugging
- Returning a default/fallback view
- Throwing an error that can be caught at the app level
This aligns with the TODO comment about specifying a default destination.
Would you like me to generate an implementation that provides graceful degradation with proper error logging?
🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 17-17: TODOs should be resolved (DI 실패 시 기본으로 갈 곳 지정)
(todo)
🤖 Prompt for AI Agents
In @Cherrish-iOS/Cherrish-iOS/Presentation/ViewFactory.swift around lines 15-21,
Replace the fatalError in makeTestView: when DIContainer.shared.resolve(type:
TestViewModel.self) returns nil, log the failure (using the app logger or
print), and return a safe fallback TestView instance instead of crashing;
implement this by either creating a lightweight DefaultTestViewModel (or a
TestViewModel.mock()/initWithDefaults()) and returning TestView(viewModel:
defaultVM), or add a TestView.init() convenience initializer that creates an
empty/placeholder UI and return that; update makeTestView to use the fallback
path and keep the method signature unchanged so callers aren’t forced to handle
throws.
sum130
left a comment
There was a problem hiding this comment.
끄아 어렵네요 이제 막 DI 이해했는데..
pr에도 설명 달아주셔서 감사합니두!! 찬찬히 읽어봤어요ㅎㅎ
soseoyo12
left a comment
There was a problem hiding this comment.
아따 어렵네요,,, 오늘안에 이해 완료 해보겠습니다
wotjs020708
left a comment
There was a problem hiding this comment.
아직 어렵네요... 파이팅합시다! 고생하셨어욤
🔗 연결된 이슈
📄 작업 내용
💻 주요 코드 설명
DIContainer란?
어제 미미나때도 나연언니가 언급해준 내용이기도 한데요. DIContainer는 Dependency Injection Container로 의존성 주입을 관리해주는 아이입니다. DIContainer가 의존성을 모두 관리하며 주입해줍니다.
만약 DIContainer 없이 그냥 우리 프로젝트 구조에서 의존성주입을 한다면, viewModel을 부를 때
뷰모델(유스케이스(레포지토리..))) 이렇게 영원히 의존성 주입을 해야하는 복잡한 코드가 나오게 됩니다.
그래서 모든 의존성을 관리해주는 DIContainer를 사용합니다.
구현
dependency를 관리하는 딕셔너리를 만듭니다.
인스턴스를 관리하는 데에는 register와 resolve 두가지 방법이 있습니다.
register는 내가 사용할 모든 인스턴스를 딕셔너리에 등록합니다.
key에는 타입이름을 String으로 저장하고, value에는 인스턴스를 만들어줄 클로저를 저장합니다.
dependencies의 Value에 () -> Any라는 클로저를 지정해주었기 때문에, register 할 때에는 T 객체를 만들어주는 클로저가 들어가게 됩니다.
resolve는 내가 객체가 필요한 시점에 컨테이너에게 특정 타입의 인스턴스를 달라고 하는 과정입니다.
dependecies 딕셔너리에서 key에 해당하는 클로저를 꺼내와서 실행합니다.
Layer 별 DI
DI되는 순서는 다음과 같습니다.
그래서 레이어 별로 register하고, 필요할 때 resolve해오는 코드를 작성합니다.
ViewFactory
뷰를 생성할 때에도 ViewModel이 필요합니다. 그래서 ViewFactory를 만들어 이곳에서 모두 관리합니다.
앱 진입 시 DI
앱 진입 시에 DIContainer의 dependencyInjection 함수를 호출 해 레이어별로 모두 register합니다.
추후에 코디네이터로 옮길 생각입니다.
To Reviewers
리뷰 많이 달아주세요~ ~~~ 질문도 편하게 하세요 !!
Summary by CodeRabbit
New Features
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.