ํ๋์ ์ธ Swift Concurrency๋ฅผ ์ํ ๊ฐ๋จํ๊ณ ๊ฐ๋ ฅํ ์์กด์ฑ ์ฃผ์ ํ๋ ์์ํฌ
์ฐธ๊ณ : ์ฝ๊ธฐ(๊ทธ๋ํ/ํต๊ณ/์ต์ ํ ์ฌ๋ถ)๋ UnifiedDI/DIContainer์ ๋๊ธฐ ํฌํผ๋ฅผ ์ฌ์ฉํ์ธ์. ๋ด๋ถ AutoDIOptimizer์ ์ฝ๊ธฐ์ฉ API๋ ์ค๋ ์ท ๊ธฐ๋ฐ ๋ด๋ถ์ฉ์ด๋ฉฐ ์ธ๋ถ ์ง์ ํธ์ถ์ ๋น๊ถ์ฅ(Deprecated)์ ๋๋ค.
๐ ๋ฌธ์: ํ๊ตญ์ด | English | ๊ณต์ ๋ฌธ์ | ๋ก๋๋งต
- โก Swift Concurrency ๋ค์ดํฐ๋ธ: async/await์ Actor ์๋ฒฝ ์ง์
- ๐ ํ์ ์์ ์ฑ: ์ปดํ์ผ ํ์ ํ์ ๊ฒ์ฆ
- ๐ TCA ์คํ์ผ ์์กด์ฑ ์ฃผ์
:
@Injected๋ก KeyPath์ ํ์ ๊ธฐ๋ฐ ์ฃผ์ ์ง์ (v3.2.0) - ๐๏ธ AppDI ๊ฐ์ํ:
AppDIManager๋ก ์๋ ์์กด์ฑ ๋ฑ๋ก (v3.2.0) - ๐ฏ Needle-style Components:
@Component๋งคํฌ๋ก๋ก 10x ๋น ๋ฅธ Needle ํธํ์ฑ (v3.2.1) - โก UnifiedRegistry: TypeSafeRegistry ํตํฉ์ผ๋ก ์ฑ๋ฅ๊ณผ ๋์์ฑ ์์ ์ฑ ํฅ์ (v3.2.1)
- ๐ค ์๋ ์ต์ ํ: ์์กด์ฑ ๊ทธ๋ํ, Actor hop ๊ฐ์ง, ํ์ ์์ ์ฑ ๊ฒ์ฆ ์๋ํ
- ๐ ๋ฐํ์ ํซํจ์ค ์ต์ ํ: TypeID + ๋ฝ-ํ๋ฆฌ ์ฝ๊ธฐ๋ก 50-80% ์ฑ๋ฅ ํฅ์
- ๐งช ํ ์คํธ ์นํ์ : ์์กด์ฑ ๋ชจํน๊ณผ ๊ฒฉ๋ฆฌ ์ง์
dependencies: [
.package(url: "https://github.com/Roy-wonji/WeaveDI.git", from: "3.2.1")
]import WeaveDI
// 1. ์ฑ ์ด๊ธฐํ - ์๋ ์์กด์ฑ ๋ฑ๋ก
@main
struct MyApp: App {
init() {
WeaveDI.Container.bootstrapInTask { @DIContainerActor _ in
await AppDIManager.shared.registerDefaultDependencies()
}
}
}
// 2. TCA ์คํ์ผ @Injected ์ฌ์ฉ (๊ถ์ฅ)
class ViewModel {
@Injected(\.userService) var userService
@Injected(ExchangeUseCaseImpl.self) var exchangeUseCase
func loadData() async {
let data = await userService.fetchData()
}
}
// 3. InjectedKey๋ก ์์กด์ฑ ์ ์
extension InjectedValues {
var userService: UserServiceProtocol {
get { self[UserServiceKey.self] }
set { self[UserServiceKey.self] = newValue }
}
}
struct UserServiceKey: InjectedKey {
static var currentValue: UserServiceProtocol = UserService()
}
// โ ๏ธ ๋ ๊ฑฐ์ Property Wrapper (v3.2.0๋ถํฐ Deprecated)
class LegacyViewController {
@Inject var userService: UserServiceProtocol? // (v3.2.0๋ถํฐ Deprecated)
@Factory var generator: PDFGenerator // ์ ์ง๋จ
@SafeInject var apiService: APIServiceProtocol? // (v3.2.0๋ถํฐ Deprecated)
}
// ๋ง์ด๊ทธ๋ ์ด์
๊ฐ์ด๋: @Injected๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
// ๋ ๋์ ํ์
์์ ์ฑ๊ณผ TCA ์คํ์ผ KeyPath ์ ๊ทผ์ ์ ๊ณตํฉ๋๋คWeaveDI๋ ์ปดํ์ผ ํ์ ์ต์ ํ์ Needle ์คํ์ผ ์ํคํ ์ฒ๋ฅผ ์ํ ๊ฐ๋ ฅํ Swift ๋งคํฌ๋ก๋ฅผ ์ ๊ณตํฉ๋๋ค.
import WeaveDI
@Component
public struct UserComponent {
@Provide var userService: UserService = UserService()
@Provide var userRepository: UserRepository = UserRepository()
@Provide var authService: AuthService = AuthService()
}
// ์ปดํ์ผ ํ์์ ์๋ ์์ฑ๋จ:
// UnifiedDI.register(UserService.self) { UserService() }
// UnifiedDI.register(UserRepository.self) { UserRepository() }
// UnifiedDI.register(AuthService.self) { AuthService() }@AutoRegister(lifetime: .singleton)
class DatabaseService: DatabaseServiceProtocol {
// ์๋์ผ๋ก UnifiedDI์ ๋ฑ๋ก๋จ
}
@AutoRegister(lifetime: .transient)
class RequestHandler: RequestHandlerProtocol {
// ๋งค๋ฒ ์ ์ธ์คํด์ค ์์ฑ
}@DIActor
public final class AutoMonitor {
public static let shared = AutoMonitor()
// ๋ชจ๋ ๋ฉ์๋๊ฐ ์๋์ผ๋ก ์ค๋ ๋ ์์ ํด์ง
public func onModuleRegistered<T>(_ type: T.Type) {
// Actor ๊ฒฉ๋ฆฌ๋ ์์ ํ ์์
}
}@DependencyGraph([
UserService.self: [UserRepository.self, Logger.self],
UserRepository.self: [DatabaseService.self],
DatabaseService.self: [],
Logger.self: []
])
class ApplicationDependencyGraph {
// โ
์ปดํ์ผ ํ์์ ์ํ ์์กด์ฑ ๊ฒ์ฆ
}| ํ๋ ์์ํฌ | ๋ฑ๋ก | ํด๊ฒฐ | ๋ฉ๋ชจ๋ฆฌ | ๋์์ฑ |
|---|---|---|---|---|
| Swinject | ~1.2ms | ~0.8ms | ๋์ | ์๋ ๋ฝ |
| Needle | ~0.8ms | ~0.6ms | ๋ณดํต | ์ ํ์ |
| WeaveDI | ~0.2ms | ~0.1ms | ๋ฎ์ | ๋ค์ดํฐ๋ธ async/await |
๋ ์์ธํ ๋งคํฌ๋ก ์ฌ์ฉ๋ฒ์ WeaveDI ๋งคํฌ๋ก ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํ์ธ์.
import WeaveDI
// ๋๊ธฐ ๋ถํธ์คํธ๋ฉ
await DIContainer.bootstrap { di in
di.register(Logger.self) { ConsoleLogger() }
di.register(Networking.self) { DefaultNetworking() }
}
// ๋น๋๊ธฐ ๋ถํธ์คํธ๋ฉ
let ok = await DIContainer.bootstrapAsync { di in
let flags = try await FeatureFlags.fetch()
di.register(FeatureFlags.self) { flags }
}
// ํผํฉ ๋ถํธ์คํธ๋ฉ
@MainActor
await DIContainer.bootstrapMixed(
sync: { di in di.register(Logger.self) { ConsoleLogger() } },
async: { di in
let analytics = await AnalyticsClient.make()
di.register(AnalyticsClient.self) { analytics }
}
)
// ์กฐ๊ฑด๋ถ ๋ถํธ์คํธ๋ฉ
_ = await DIContainer.bootstrapIfNeeded { di in
di.register(Config.self) { LocalConfig() }
}
// ๋ณด์ฅ/ํ
์คํธ
DIContainer.ensureBootstrapped()
@MainActor
DIContainer.resetForTesting() // DEBUG ์ ์ฉ์ฝ๊ธฐ(๊ทธ๋ํ/ํต๊ณ/์ต์ ํ ์ฌ๋ถ)๋ UnifiedDI/DIContainer์ ๋๊ธฐ ํฌํผ ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค. ๋ด๋ถ AutoDIOptimizer ๋ฆฌ๋๋ ์ค๋ ์ท ๊ธฐ๋ฐ ๋ด๋ถ์ฉ์ด๋ฉฐ, ์ธ๋ถ ์ง์ ํธ์ถ์ ๋น๊ถ์ฅ(Deprecated)์ ๋๋ค.
// ๊ธฐ๋ณธ ๋ฑ๋ก (๊ถ์ฅ)
let service = UnifiedDI.register(ServiceProtocol.self) {
ServiceImpl()
}
// KeyPath ๋ฑ๋ก
let repository = UnifiedDI.register(\.userRepository) {
UserRepositoryImpl()
}
// ์กฐ๊ฑด๋ถ ๋ฑ๋ก
let service = UnifiedDI.Conditional.registerIf(
ServiceProtocol.self,
condition: isProduction,
factory: { ProductionService() },
fallback: { MockService() }
)
// ์ค์ฝํ ๊ธฐ๋ฐ ๋ฑ๋ก
let sessionService = UnifiedDI.registerScoped(
SessionService.self,
scope: .session
) {
SessionServiceImpl()
}| Property Wrapper | ์ฉ๋ | ์์ | ์ํ |
|---|---|---|---|
@Injected |
TCA ์คํ์ผ ์ฃผ์ (๊ถ์ฅ) | @Injected(\.service) var service |
โ v3.2.0 |
@Factory |
ํฉํ ๋ฆฌ ํจํด (์ ์ธ์คํด์ค) | @Factory var generator: Generator |
โ ์ ์ง |
@Inject |
๊ธฐ๋ณธ ์ฃผ์ (๋ ๊ฑฐ์) | @Inject var service: Service? |
|
@SafeInject |
์์ ํ ์ฃผ์ (๋ ๊ฑฐ์) | @SafeInject var api: API? |
๐ ๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋: @Injected ๋ฌธ์ | AppDI ๊ฐ์ํ
// ์ผ๋ฐ ํด๊ฒฐ
let service = UnifiedDI.resolve(ServiceProtocol.self)
// ํ์ ํด๊ฒฐ (์์ผ๋ฉด ํฌ๋์)
let logger = UnifiedDI.requireResolve(Logger.self)
// ๊ธฐ๋ณธ๊ฐ ํฌํจ ํด๊ฒฐ
let cache = UnifiedDI.resolve(Cache.self, default: MemoryCache())๋ณ๋ ์ค์ ์์ด ์๋์ผ๋ก ์คํ๋ฉ๋๋ค:
// ๋ฑ๋ก/ํด๊ฒฐ๋ง ํ๋ฉด ์๋์ผ๋ก ๊ทธ๋ํ ์์ฑ ๋ฐ ์ต์ ํ
let service = UnifiedDI.register(UserService.self) { UserServiceImpl() }
let resolved = UnifiedDI.resolve(UserService.self)
// ์๋ ์์ง๋ ์ ๋ณด๋ LogMacro๋ก ์๋ ์ถ๋ ฅ๋ฉ๋๋ค
// ๐ Auto tracking registration: UserService
// โก Auto optimized: UserService (10 uses)// ํด๊ฒฐํ๊ธฐ๋ง ํ๋ฉด ์๋์ผ๋ก Actor hop ๊ฐ์ง
await withTaskGroup(of: Void.self) { group in
for _ in 1...10 {
group.addTask {
_ = UnifiedDI.resolve(UserService.self) // Actor hop ์๋ ๊ฐ์ง
}
}
}
// ์๋ ๋ก๊ทธ (5ํ ์ด์ hop ๋ฐ์ ์):
// ๐ฏ Actor optimization suggestion for UserService: MainActor๋ก ์ด๋ ๊ถ์ฅ// ํด๊ฒฐ ์ ์๋์ผ๋ก ํ์
์์ ์ฑ ๊ฒ์ฆ
let service = UnifiedDI.resolve(UserService.self)
// ์๋ ๋ก๊ทธ (๋ฌธ์ ๊ฐ์ง ์):
// ๐ Type safety issue: UserService is not Sendable
// ๐จ Auto safety check: UserService resolved to nil// ์ฌ๋ฌ ๋ฒ ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก ์ต์ ํ๋จ
for _ in 1...15 {
let service = UnifiedDI.resolve(UserService.self)
}
// ์ต์ ํ๋ ํ์
๋ค์ ์๋์ผ๋ก ๋ก๊น
๋ฉ๋๋ค
// โก Auto optimized: UserService (15 uses)// ์ฌ์ฉ ํต๊ณ๋ 30์ด๋ง๋ค ์๋์ผ๋ก ๋ก๊น
๋ฉ๋๋ค
// ๐ [AutoDI] Current stats: ["UserService": 15, "DataRepository": 8]๊ณ ์ฑ๋ฅ์ด ์๊ตฌ๋๋ ์ฑ์ ์ํ ๋ฏธ์ธ ์ต์ ํ ๊ธฐ๋ฅ์ ๋๋ค.
import WeaveDI
// ์ต์ ํ ๋ชจ๋ ํ์ฑํ (๊ธฐ์กด API๋ ๊ทธ๋๋ก ์๋)
UnifiedRegistry.shared.enableOptimization()
// ๊ธฐ์กด ์ฝ๋๋ ๋ณ๊ฒฝ ์์ด ์ฑ๋ฅ ํฅ์
let service = await UnifiedDI.resolve(UserService.self)- TypeID + ์ธ๋ฑ์ค ์ ๊ทผ: ๋์ ๋๋ฆฌ โ ๋ฐฐ์ด ์ฌ๋กฏ์ผ๋ก O(1) ์ ๊ทผ
- ๋ฝ-ํ๋ฆฌ ์ฝ๊ธฐ: ์ค๋ ์ท ๋ฐฉ์์ผ๋ก ์ฝ๊ธฐ ๊ฒฝํฉ ์ ๊ฑฐ
- ์ธ๋ผ์ธ ์ต์ ํ: ํจ์ ํธ์ถ ์ค๋ฒํค๋ ์ถ์
- ํฉํ ๋ฆฌ ์ฒด์ด๋ ์ ๊ฑฐ: ์ง์ ํธ์ถ ๊ฒฝ๋ก๋ก ์ค๊ฐ ๋จ๊ณ ์ ๊ฑฐ
- ์ค์ฝํ๋ณ ์ ์ฅ์: ์ฑ๊ธํค/์ธ์ /์์ฒญ ์ค์ฝํ ๋ถ๋ฆฌ ์ต์ ํ
| ์๋๋ฆฌ์ค | ๊ฐ์ ์จ | ์ค๋ช |
|---|---|---|
| ๋จ์ผ ์ค๋ ๋ resolve | 50-80% | TypeID + ์ง์ ์ ๊ทผ |
| ๋ฉํฐ์ค๋ ๋ ์ฝ๊ธฐ | 2-3๋ฐฐ | ๋ฝ-ํ๋ฆฌ ์ค๋ ์ท |
| ๋ณต์กํ ์์กด์ฑ | 20-40% | ์ฒด์ธ ํ๋ํผํ |
swift run -c release Benchmarks --count 100k --quick์์ธํ ๋ด์ฉ์ PERFORMANCE-OPTIMIZATION.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
UnifiedDI.setLogLevel(.registration) // ๋ฑ๋ก๋ง ๋ก๊น
UnifiedDI.setLogLevel(.optimization) // ์ต์ ํ๋ง ๋ก๊น
UnifiedDI.setLogLevel(.errors) // ์๋ฌ/๊ฒฝ๊ณ ๋ง ๋ก๊น
UnifiedDI.setLogLevel(.off) // ๋ก๊น
๋๊ธฐ// ํ
์คํธ์ฉ ์ด๊ธฐํ
@MainActor
override func setUp() {
UnifiedDI.releaseAll()
// ํ
์คํธ์ฉ ์์กด์ฑ ๋ฑ๋ก
_ = UnifiedDI.register(UserService.self) {
MockUserService()
}
}// ๐ ์๋ ์์ฑ๋ ์์กด์ฑ ๊ทธ๋ํ
UnifiedDI.autoGraph
// โก ์๋ ์ต์ ํ๋ ํ์
๋ค
UnifiedDI.optimizedTypes
// ๐ ์๋ ์์ง๋ ์ฌ์ฉ ํต๊ณ
UnifiedDI.stats
// ๐ฏ Actor ์ต์ ํ ์ ์ ๋ชฉ๋ก
UnifiedDI.actorOptimizations
// ๐ ํ์
์์ ์ฑ ์ด์ ๋ชฉ๋ก
UnifiedDI.typeSafetyIssues
//
// โก Actor hop ํต๊ณ
UnifiedDI.actorHopStats
// ๐ ๋น๋๊ธฐ ์ฑ๋ฅ ํต๊ณ (๋ฐ๋ฆฌ์ด)
UnifiedDI.asyncPerformanceStats์๋ AutoDIOptimizer์ ์ฝ๊ธฐ์ฉ API๋ ๋ด๋ถ ์ค๋ ์ท ๊ธฐ๋ฐ์ผ๋ก ์ฌ๊ตฌ์ฑ๋์์ผ๋ฉฐ, ์ธ๋ถ ์ฌ์ฉ์ ๋น๊ถ์ฅ(Deprecated)์ ๋๋ค. UnifiedDI/DIContainer์ ๋๊ธฐ ํฌํผ๋ฅผ ์ฌ์ฉํ์ธ์.
| Deprecated (AutoDIOptimizer) | Replacement |
|---|---|
getCurrentStats() |
UnifiedDI.stats() / DIContainer.getUsageStatistics() |
visualizeGraph() |
UnifiedDI.autoGraph() / DIContainer.getAutoGeneratedGraph() |
getFrequentlyUsedTypes() |
UnifiedDI.optimizedTypes() / DIContainer.getOptimizedTypes() |
getDetectedCircularDependencies() |
UnifiedDI.circularDependencies() / DIContainer.getDetectedCircularDependencies() |
isOptimized(_:) |
UnifiedDI.isOptimized(_:) / DIContainer.isAutoOptimized(_:) |
getActorOptimizationSuggestions() |
UnifiedDI.actorOptimizations |
getDetectedTypeSafetyIssues() |
UnifiedDI.typeSafetyIssues |
getDetectedAutoFixedTypes() |
UnifiedDI.autoFixedTypes |
getActorHopStats() |
UnifiedDI.actorHopStats |
getAsyncPerformanceStats() |
UnifiedDI.asyncPerformanceStats |
getRecentGraphChanges(...) |
UnifiedDI.getGraphChanges(...) |
getCurrentLogLevel() |
UnifiedDI.logLevel / UnifiedDI.getLogLevel() |
๋ด๋ถ ์ฉ๋๋ก๋
AutoDIOptimizer.readSnapshot()๋ฅผ ํตํด ์ค๋ ์ท์ ์ฝ์ด ํ์ํ ์ ๋ณด๋ฅผ ๊ณ์ฐํ์ธ์.
์คํ:
swift run -c release Benchmarks -- --count 100000 --debounce 100
# ์ฌ๋ฌ ์กฐํฉ ํ
์คํธ(10k/100k/1M ร 50/100/200ms)
swift run -c release Benchmarks์ถ๋ ฅ ์์:
๐ Bench: counts=[10000, 100000, 1000000], debounces=[50, 100, 200] (ms)
debounce= 50ms, n= 10000 | total= 12.34ms | p50= 0.010 p95= 0.020 p99= 0.030
...
CSV ์ ์ฅ ๋ฐ ์ฐจํธ ์์ฑ(์ ํ)
# CSV์ ๋์ ์ ์ฅ
swift run -c release Benchmarks -- --count 100000 --debounce 100 --csv bench.csv
# ๋น ๋ฅธ ํ์ธ(์ฒซ ์กฐํฉ๋ง)
swift run -c release Benchmarks -- --quick --csv bench.csv
# ํ
์คํธ ์์ฝ + PNG ์ฐจํธ(์ ํ, matplotlib ํ์)
python3 Scripts/plot_bench.py --csv bench.csv --out bench_plotmatplotlib์ด ์์ผ๋ฉด ํ ์คํธ ์์ฝ๋ง ์ถ๋ ฅํฉ๋๋ค. ์ค์น:
pip install matplotlib
- API ๋ฌธ์
- ๋ก๋๋งต (v3.2.0) - ํ์ฌ ๋ฒ์ ๋ฐ ํฅํ ๊ณํ
- @Injected ๊ฐ์ด๋ - TCA ์คํ์ผ ์์กด์ฑ ์ฃผ์
- TCA ํตํฉ ๊ฐ์ด๋ - Composable Architecture์์ WeaveDI ์ฌ์ฉ
- AppDI ๊ฐ์ํ - ์๋ ์์กด์ฑ ๋ฑ๋ก
- ์๋ ์ต์ ํ ๊ฐ์ด๋
- Property Wrapper ๊ฐ์ด๋
- ๋ง์ด๊ทธ๋ ์ด์ 3.0.0
- ์๋ฏธ: ๋ฐ๋ณตยทํ๋ ์ ๋ฃจํ ๋ฑ ํซํจ์ค์์ ๋ฐํ์ ํด์์ ์์ ์ ์ ์์ฑ/์บ์๋ก ๋์ฒดํด ๋น์ฉ์ 0์ ์๋ ดํ๊ฒ ํฉ๋๋ค.
- ์ฌ์ฉ ์์น: ์ฝ๋์
#if USE_STATIC_FACTORY๋ถ๊ธฐ(์ด๋ฏธ ํ ํ๋ฆฟ ํฌํจ) โ ๋น๋ ํ๋๊ทธ๋ก on/off - ํ์ฑํ ๋ฐฉ๋ฒ
- Xcode: Target โ Build Settings โ Other Swift Flags(Release ๋๋ ์ ์ฉ ์คํด)์
-DUSE_STATIC_FACTORY์ถ๊ฐ - SPM CLI:
swift build -c release -Xswiftc -DUSE_STATIC_FACTORY- ํ
์คํธ:
swift test -c release -Xswiftc -DUSE_STATIC_FACTORY
- ํ
์คํธ:
- Xcode: Target โ Build Settings โ Other Swift Flags(Release ๋๋ ์ ์ฉ ์คํด)์
- ๋ฐ๋์ Release + WMO(WholeโModule Optimization)์์ ์ธก์ ํ์ธ์.
- Xcode: Release ์คํด์ผ๋ก ์คํ(Release๋ ๊ธฐ๋ณธ์ ์ผ๋ก WMO ์ ์ฉ)
- SPM:
swift build -c release,swift test -c release
- ๋
ธ์ด์ฆ ์ต์ํ ํ
- ๋ก๊ทธ ๋ ๋ฒจ ๋ฎ์ถ๊ธฐ:
UnifiedDI.setLogLevel(.errors)๋๋.off - ์๋ ์ต์ ํ ON:
UnifiedDI.configureOptimization(...),UnifiedDI.setAutoOptimization(true) - ๋ฐ๋ณต ๋ฃจํ๋ resolve ์บ์(๋ฃจํ ๋ฐ 1ํ ํ๋ณด โ ์์์๋ ์ฌ์ฌ์ฉ)
- ๋ก๊ทธ ๋ ๋ฒจ ๋ฎ์ถ๊ธฐ:
| ํน์ง | Needle | WeaveDI | ๊ฒฐ๊ณผ |
|---|---|---|---|
| ์ปดํ์ผํ์ ์์ ์ฑ | โ ์ฝ๋ ์์ฑ | โ ๋งคํฌ๋ก ๊ธฐ๋ฐ | ๋๋ฑ |
| ๋ฐํ์ ์ฑ๋ฅ | โ ์ ๋ก ์ฝ์คํธ | โ ์ ๋ก ์ฝ์คํธ + Actor ์ต์ ํ | WeaveDI ์ฐ์น |
| Swift 6 ์ง์ | โ ์๋ฒฝ ๋ค์ดํฐ๋ธ | WeaveDI ์ฐ์น | |
| ์ฝ๋ ์์ฑ ํ์ | โ ํ์ | โ ์ ํ์ | WeaveDI ์ฐ์น |
| ํ์ต ๊ณก์ | โ ๊ฐํ๋ฆ | โ ์ ์ง์ | WeaveDI ์ฐ์น |
| ๋ง์ด๊ทธ๋ ์ด์ | โ All-or-nothing | โ ์ ์ง์ | WeaveDI ์ฐ์น |
// Needle ์์ค ์ฑ๋ฅ + ๋ ์ฌ์ด ์ฌ์ฉ๋ฒ
UnifiedDI.enableStaticOptimization() // Needle๊ณผ ๋์ผํ ์ ๋ก ์ฝ์คํธ
@DependencyGraph([ // ์ปดํ์ผํ์ ๊ฒ์ฆ
UserService.self: [NetworkService.self, Logger.self]
])
extension WeaveDI {}
print(UnifiedDI.migrateFromNeedle()) // Needle โ WeaveDI ๋ง์ด๊ทธ๋ ์ด์
๊ฐ์ด๋- ๋ณ๋ ์ค์ ์์ด Actor hop ๊ฐ์ง, ํ์ ์์ ์ฑ ๊ฒ์ฆ, ์ฑ๋ฅ ์ต์ ํ๊ฐ ์๋ ์คํ
- ์ค์๊ฐ ๋ถ์์ผ๋ก 30์ด๋ง๋ค ์ต์ ํ ์ํ (Needle์ ์๋ ๊ธฐ๋ฅ)
- ๊ฐ๋ฐ์ ์นํ์ ์ ์์ผ๋ก ์ฑ๋ฅ ๊ฐ์ ์ ์๋ ์๋ด
- Actor ์์ ์ฑ ์๋ ๊ฒ์ฆ ๋ฐ ์ต์ ํ ์ ์
- async/await ์๋ฒฝ ์ง์ (Needle์ ์ ํ์ )
- Sendable ํ๋กํ ์ฝ ์ค์ ๊ฒ์ฆ
- 2๊ฐ Property Wrapper๋ง์ผ๋ก ๋ชจ๋ ์ฃผ์
ํจํด ์ปค๋ฒ (
@Injected,@Factory)- ์ฐธ๊ณ :
@Inject์@SafeInject๋ v3.2.0๋ถํฐ Deprecated. @Injected ์ฌ์ฉ ๊ถ์ฅ
- ์ฐธ๊ณ :
- ํ์ ์์ ํ KeyPath ๊ธฐ๋ฐ ๋ฑ๋ก
- ์ง๊ด์ ์ธ ์กฐ๊ฑด๋ถ ๋ฑ๋ก
MIT License. ์์ธํ ๋ด์ฉ์ LICENSE ํ์ผ์ ์ฐธ๊ณ ํ์ธ์.
์์์ง (Roy, Wonji Suh)
- ๐ง [email protected]
- ๐ GitHub
WeaveDI๋ฅผ ๋ ์ข๊ฒ ๋ง๋ค์ด์ฃผ์ธ์!
- ์ด์ ์ ๊ธฐ: GitHub Issues์์ ๋ฒ๊ทธ ๋ฆฌํฌํธ๋ ๊ธฐ๋ฅ ์์ฒญ
- Pull Request: ๊ฐ์ ์ฌํญ์ด๋ ์๋ก์ด ๊ธฐ๋ฅ์ ์ง์ ๊ตฌํํด์ ๊ธฐ์ฌ
- ๋ฌธ์ ๊ฐ์ : README๋ ๋ฌธ์์ ์คํ, ๊ฐ์ ์ฌํญ ์ ์
git clone https://github.com/Roy-wonji/WeaveDI.git
cd WeaveDI
swift build
swift testWeaveDI์ ํจ๊ป ๋ ๋์ Swift ๊ฐ๋ฐ ๊ฒฝํ์ ๋ง๋ค์ด๊ฐ์ธ์! ๐
โญ ์ด ํ๋ก์ ํธ๊ฐ ๋์์ด ๋์๋ค๋ฉด Star๋ฅผ ๋๋ฌ์ฃผ์ธ์! โญ