Skip to content

Roy-wonji/WeaveDI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

375 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

WeaveDI โ€“ App Image

WeaveDI

SPM Swift License Platform Docs

ํ˜„๋Œ€์ ์ธ Swift Concurrency๋ฅผ ์œ„ํ•œ ๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ์˜์กด์„ฑ ์ฃผ์ž… ํ”„๋ ˆ์ž„์›Œํฌ

์ฐธ๊ณ : ์ฝ๊ธฐ(๊ทธ๋ž˜ํ”„/ํ†ต๊ณ„/์ตœ์ ํ™” ์—ฌ๋ถ€)๋Š” UnifiedDI์˜ ๋™๊ธฐ ํ—ฌํผ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋‚ด๋ถ€ AutoDIOptimizer์˜ ์ฝ๊ธฐ์šฉ API๋Š” ์Šค๋ƒ…์ƒท ๊ธฐ๋ฐ˜ ๋‚ด๋ถ€์šฉ์ด๋ฉฐ ์™ธ๋ถ€ ์ง์ ‘ ํ˜ธ์ถœ์€ ๋น„๊ถŒ์žฅ(Deprecated)์ž…๋‹ˆ๋‹ค.

๐Ÿ“– ๋ฌธ์„œ: ํ•œ๊ตญ์–ด | English | ๊ณต์‹ ๋ฌธ์„œ | ๋กœ๋“œ๋งต

๐ŸŽฏ ํ•ต์‹ฌ ํŠน์ง•

  • ๐Ÿš€ TCA ์Šคํƒ€์ผ ๊ทน๋‹จ์  ๋‹จ์ˆœํ™”: @Injected var service: Service - ํ‚คํŒจ์Šค ์—†์ด ํƒ€์ž…๋งŒ์œผ๋กœ! (v4.0.0)
  • ๐ŸŽจ SwiftUI ์Šคํƒ€์ผ ์„ ์–ธ์  ๋“ฑ๋ก: @DependencyConfiguration Result Builder๋กœ ์˜์กด์„ฑ ์„ ์–ธ (v4.0.0)
  • ๐ŸŒ ํ™˜๊ฒฝ๋ณ„ ์ž๋™ ์„ค์ •: DependencyEnvironment.production/development/testing ์ž๋™ ๋ถ„๊ธฐ (v4.0.0)
  • ๐Ÿ“ฆ ๊ทน๋‹จ์  ๊ฒฝ๋Ÿ‰ํ™”: 9๊ฐœ ๋ชจ๋“ˆ โ†’ 3๊ฐœ ๋ชจ๋“ˆ๋กœ 70% ์ถ•์†Œ, ์ปดํŒŒ์ผ ์‹œ๊ฐ„ 50% ๋‹จ์ถ• (v4.0.0)
  • โšก Swift 6 ์™„๋ฒฝ ์ง€์›: Strict Concurrency, Modern Macros, Structured Concurrency ๋„ค์ดํ‹ฐ๋ธŒ
  • ๐Ÿ”’ ํƒ€์ž… ์•ˆ์ „์„ฑ: ์ปดํŒŒ์ผ ํƒ€์ž„ ํƒ€์ž… ๊ฒ€์ฆ ๋ฐ ์ž๋™ ์˜์กด์„ฑ ์ฃผ์ž…
  • ๐Ÿค– ์ž๋™ ์ตœ์ ํ™”: ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„, Actor hop ๊ฐ์ง€, ํƒ€์ž… ์•ˆ์ „์„ฑ ๊ฒ€์ฆ ์ž๋™ํ™”
  • ๐Ÿงช ํ…Œ์ŠคํŠธ ์นœํ™”์ : ์˜์กด์„ฑ ๋ชจํ‚น๊ณผ ๊ฒฉ๋ฆฌ ์ง€์›, SwiftUI Preview ์ตœ์ ํ™”

๐ŸŽ‰ v4.0.0 ์ฃผ์š” ๊ฐœ์„ ์‚ฌํ•ญ

๐Ÿ“Š Before vs After ๋น„๊ต

๊ตฌ๋ถ„ Before (v3.x) After (v4.0.0) ๊ฐœ์„ ์œจ
๋ชจ๋“ˆ ์ˆ˜ 9๊ฐœ ๋ณต์žกํ•œ ๋ชจ๋“ˆ 3๊ฐœ ํ•ต์‹ฌ ๋ชจ๋“ˆ 70% ๊ฐ์†Œ
๋“ฑ๋ก ์ฝ”๋“œ 50+ ์ค„ boilerplate 5์ค„ ์„ ์–ธ์  ๋“ฑ๋ก 90% ๊ฐ์†Œ
์‚ฌ์šฉ๋ฒ• @Injected(\.keyPath) @Injected var service: Service ํ‚คํŒจ์Šค ๋ถˆํ•„์š”
์ปดํŒŒ์ผ ์‹œ๊ฐ„ ๊ธฐ์ค€ 50% ๋‹จ์ถ• 2๋ฐฐ ๋นจ๋ผ์ง
ํ•™์Šต ๋น„์šฉ ๋†’์Œ (๋ณต์žกํ•œ API) ๋‚ฎ์Œ (TCA ์Šคํƒ€์ผ) ๊ทน๋‹จ์  ๋‹จ์ˆœํ™”

๐ŸŽฏ ํ•ต์‹ฌ ๊ฐœ์„ ์‚ฌํ•ญ

  • ๐Ÿš€ @Injected ํ˜์‹ : ํ‚คํŒจ์Šค ์—†์ด ํƒ€์ž…๋งŒ์œผ๋กœ ์˜์กด์„ฑ ์ฃผ์ž…!
  • ๐ŸŽจ SwiftUI ์Šคํƒ€์ผ: @DependencyConfiguration Result Builder๋กœ ์„ ์–ธ์  ๋“ฑ๋ก
  • ๐ŸŒ ํ™˜๊ฒฝ๋ณ„ ์ž๋™ ๋ถ„๊ธฐ: development/production/testing/preview ์ž๋™ ์„ ํƒ
  • ๐Ÿ“ฆ ๊ทน๋‹จ์  ๊ฒฝ๋Ÿ‰ํ™”: 9๊ฐœ ๋ชจ๋“ˆ โ†’ 3๊ฐœ ๋ชจ๋“ˆ, ์˜์กด์„ฑ ์ฒด์ธ ๋‹จ์ˆœํ™”
  • โœ… 100% ํ˜ธํ™˜์„ฑ: ๊ธฐ์กด ์ฝ”๋“œ ์ˆ˜์ • ์—†์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๐Ÿš€ ๋น ๋ฅธ ์‹œ์ž‘

์„ค์น˜

dependencies: [
    .package(url: "https://github.com/Roy-wonji/WeaveDI.git", from: "3.4.0")
]

๐Ÿš€ ์ƒˆ๋กœ์šด ์‚ฌ์šฉ๋ฒ• (v4.0.0) - ์—„์ฒญ ๊ฐ„๋‹จํ•ด์กŒ์Šต๋‹ˆ๋‹ค!

import WeaveDI

// 1. ๐Ÿ“ฆ SwiftUI ์Šคํƒ€์ผ ์„ ์–ธ์  ๋“ฑ๋ก (90% ์ฝ”๋“œ ๊ฐ์†Œ!)
@DependencyConfiguration
var appDependencies {
    UserServiceImpl()           // UserService๋กœ ์ž๋™ ๋“ฑ๋ก
    RepositoryImpl()            // Repository๋กœ ์ž๋™ ๋“ฑ๋ก

    // ํ™˜๊ฒฝ๋ณ„ ์ž๋™ ๋ถ„๊ธฐ
    #if DEBUG
    ConsoleLogger() as Logger   // ๊ฐœ๋ฐœ์šฉ ๋กœ๊ฑฐ
    #else
    ProductionLogger() as Logger // ํ”„๋กœ๋•์…˜ ๋กœ๊ฑฐ
    #endif
}

// 2. ์•ฑ ์‹œ์ž‘ ์‹œ ํ•œ ์ค„ ์„ค์ •
appDependencies.configure()

// 3. ๐ŸŽฏ ํƒ€์ž…๋งŒ์œผ๋กœ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ! (ํ‚คํŒจ์Šค ์—†์Œ)
class ViewModel: ObservableObject {
    @Injected var userService: UserService     // โœ… ํƒ€์ž…๋งŒ์œผ๋กœ!
    @Injected var repository: Repository       // โœ… ํ‚คํŒจ์Šค ๋ถˆํ•„์š”!
    @Injected var logger: Logger              // โœ… ํ™˜๊ฒฝ๋ณ„ ์ž๋™ ์„ ํƒ!

    func loadData() async {
        let data = await userService.fetchData()
        logger.log("Data loaded!")
    }
}

// 4. ๐ŸŒ ํ™˜๊ฒฝ๋ณ„ ์„ค์ • (์ž๋™ ๋ถ„๊ธฐ)
#if DEBUG
DependencyEnvironment.development {
    MockUserService() as UserService       // ๊ฐœ๋ฐœ์šฉ Mock
    ConsoleLogger() as Logger              // ๋””๋ฒ„๊ทธ ๋กœ๊ฑฐ
}.configure()
#else
DependencyEnvironment.production {
    UserServiceImpl() as UserService       // ์‹ค์ œ ๊ตฌํ˜„์ฒด
    ProductionLogger() as Logger           // ํ”„๋กœ๋•์…˜ ๋กœ๊ฑฐ
}.configure()
#endif

โšก ๊ธฐ์กด ์‚ฌ์šฉ๋ฒ•๋„ 100% ํ˜ธํ™˜ (Breaking Change ์—†์Œ)

// ๊ธฐ์กด ํ‚คํŒจ์Šค ๋ฐฉ์‹๋„ ๊ทธ๋Œ€๋กœ ๋™์ž‘
@Injected(\.userService) var userService: UserService  // โœ… ์—ฌ์ „ํžˆ ๋™์ž‘

// ๊ธฐ์กด UnifiedDI API๋„ ๊ทธ๋Œ€๋กœ ๋™์ž‘
UnifiedDI.register(UserService.self) { UserServiceImpl() }  // โœ… ์—ฌ์ „ํžˆ ๋™์ž‘

์•ฑ ๋ชจ๋“ˆ ๋“ฑ๋ก (์˜ต์…˜: WeaveDIAppDI)

import WeaveDI
import WeaveDIAppDI

await UnifiedDI.bootstrap { _ in
    await UnifiedDI.registerDi { register in
        [
            register.authRepositoryImplModule(),
            register.authUseCaseImplModule()
        ]
    }
}

DiModuleFactory - ๊ณตํ†ต DI ์˜์กด์„ฑ ๊ด€๋ฆฌ (v3.3.4+)

WeaveDI v3.3.4๋ถ€ํ„ฐ ๊ณตํ†ต DI ์˜์กด์„ฑ(Logger, Config ๋“ฑ)์„ ๋” ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” DiModuleFactory๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

import WeaveDI
import WeaveDIAppDI

// DiModuleFactory ์‚ฌ์šฉ๋ฒ•
var diFactory = DiModuleFactory()

// ๊ณตํ†ต DI ์˜์กด์„ฑ ์ถ”๊ฐ€ (์‹ค์ œ API)
diFactory.addDependency(Logger.self) {
    ConsoleLogger()
}

diFactory.addDependency(APIConfig.self) {
    APIConfig(baseURL: "https://api.example.com")
}

// ModuleFactoryManager์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ
var factoryManager = ModuleFactoryManager()
factoryManager.diFactory = diFactory

// ๋‹ค๋ฅธ ํŒฉํ† ๋ฆฌ๋„ ํ•จ๊ป˜ ์„ค์ • ๊ฐ€๋Šฅ
factoryManager.repositoryFactory.addRepository(UserRepository.self) {
    UserRepositoryImpl()
}

factoryManager.useCaseFactory.addUseCase(
    AuthUseCase.self,
    repositoryType: UserRepository.self,
    repositoryFallback: { UserRepositoryImpl() }
) { repo in
    AuthUseCaseImpl(repository: repo)
}

// ๋ชจ๋“  ๋ชจ๋“ˆ์„ DI ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก
await factoryManager.registerAll(to: WeaveDI.Container.live)

์ฃผ์š” ํŠน์ง•:

  • ๐Ÿ“ฆ ๊ณตํ†ต ์˜์กด์„ฑ ๊ด€๋ฆฌ: Logger, Config ๋“ฑ ์•ฑ ์ „๋ฐ˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์˜์กด์„ฑ์„ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌ
  • ๐Ÿ”„ ์ž๋™ ๋“ฑ๋ก: ModuleFactoryManager์™€ ์—ฐ๋™ํ•˜์—ฌ ์ž๋™์œผ๋กœ DI ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก
  • ๐ŸŽฏ ํƒ€์ž… ์•ˆ์ „์„ฑ: ์ปดํŒŒ์ผ ํƒ€์ž„์— ํƒ€์ž… ์•ˆ์ „์„ฑ ๋ณด์žฅ

๐Ÿ†• ์ตœ์‹  ์—…๋ฐ์ดํŠธ (v3.4.0)

WeaveDI.builder ํŒจํ„ด ์ง€์› ๐Ÿ—๏ธ

์ƒˆ๋กœ์šด fluent API๋กœ ๋”์šฑ ์ง๊ด€์ ์ธ ์˜์กด์„ฑ ๋“ฑ๋ก์ด ๊ฐ€๋Šฅํ•ด์กŒ์Šต๋‹ˆ๋‹ค:

// ์ƒˆ๋กœ์šด ๋นŒ๋” ํŒจํ„ด - ํƒ€์ž… ์ถ”๋ก ์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ!
WeaveDI.builder
    .register { UserServiceImpl() }    // UserService๋กœ ์ž๋™ ๋“ฑ๋ก
    .register { ConsoleLogger() }      // Logger๋กœ ์ž๋™ ๋“ฑ๋ก
    .register { NetworkClientImpl() }  // NetworkClient๋กœ ์ž๋™ ๋“ฑ๋ก
    .configure()

// ๊ฐœ๋ณ„ ๋“ฑ๋ก๋„ ๊ฐ€๋Šฅ
WeaveDI.register { UserServiceImpl() }  // ํ•œ ์ค„๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ

// ํ™˜๊ฒฝ๋ณ„ ๋“ฑ๋ก
WeaveDI.registerForEnvironment { env in
    if env.isDebug {
        env.register { MockUserService() as UserService }
        env.register { DebugLogger() as Logger }
    } else {
        env.register { UserServiceImpl() as UserService }
        env.register { ProductionLogger() as Logger }
    }
}

SwiftUI ์Šคํƒ€์ผ @DependencyConfiguration โšก

SwiftUI์˜ ViewBuilder์ฒ˜๋Ÿผ ์„ ์–ธ์ ์œผ๋กœ ์˜์กด์„ฑ์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// SwiftUI ์Šคํƒ€์ผ ์„ ์–ธ์  ๋“ฑ๋ก
@DependencyConfiguration
var appDependencies {
    UserServiceImpl()           // UserService๋กœ ์ž๋™ ๋“ฑ๋ก
    RepositoryImpl()            // Repository๋กœ ์ž๋™ ๋“ฑ๋ก

    // ์กฐ๊ฑด๋ถ€ ๋“ฑ๋ก๋„ ์ง€์›
    if ProcessInfo.processInfo.environment["DEBUG"] != nil {
        DebugLogger() as Logger
    } else {
        ProductionLogger() as Logger
    }
}

// ์•ฑ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ
appDependencies.configure()

// ํ™˜๊ฒฝ๋ณ„ ์„ค์ •๋„ ์ง€์›
let productionDeps = DependencyEnvironment.production {
    UserServiceImpl()
    ProductionLogger() as Logger
    RealNetworkClient() as NetworkClient
}

let developmentDeps = DependencyEnvironment.development {
    UserServiceImpl()
    ConsoleLogger() as Logger
    MockNetworkClient() as NetworkClient
}

#if DEBUG
developmentDeps.configure()
#else
productionDeps.configure()
#endif

๋ชจ๋“ˆ ๊ตฌ์กฐ ๊ฐœ์„  ๐Ÿ“ฆ

WeaveDI๋Š” ์ด์ œ ๋ช…ํ™•ํ•œ ์—ญํ•  ๋ถ„๋ฆฌ๋กœ ๋”์šฑ ์ฒด๊ณ„์ ์œผ๋กœ ๊ตฌ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • WeaveDICore: ํ•ต์‹ฌ DI ์—”์ง„ (@Injected, UnifiedDI, DIContainer)
  • WeaveDIAppDI: ์•ฑ ๋ ˆ๋ฒจ DI ๊ด€๋ฆฌ (ModuleFactoryManager, DiModuleFactory)
  • WeaveDITCA: TCA ์ „์šฉ ํ†ตํ•ฉ (์ถฉ๋Œ ํ•ด๊ฒฐ ์™„๋ฃŒ)
  • WeaveDIMacros: Swift ๋งคํฌ๋กœ ์ง€์› (@Component, @AutoRegister)
  • WeaveDIOptimizations: ์„ฑ๋Šฅ ์ตœ์ ํ™” (AutoDI, ๊ทธ๋ž˜ํ”„ ์ตœ์ ํ™”)
  • WeaveDIMonitoring: ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง (์„ฑ๋Šฅ ์ถ”์ , ํ—ฌ์Šค์ฒดํฌ)
  • WeaveDINeedleCompat: Uber Needle ํ˜ธํ™˜์„ฑ
  • WeaveDICompat: ๋ ˆ๊ฑฐ์‹œ ํ˜ธํ™˜์„ฑ ์ง€์›
  • WeaveDITools: CLI ๋„๊ตฌ์™€ ์œ ํ‹ธ๋ฆฌํ‹ฐ

TCA ์ถฉ๋Œ ํ•ด๊ฒฐ ๐Ÿ”ง

The Composable Architecture์™€์˜ ํƒ€์ž… ์ถฉ๋Œ ๋ฌธ์ œ๊ฐ€ ์™„์ „ํžˆ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

// TCA์™€ WeaveDI๋ฅผ ํ•จ๊ป˜ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ
struct AppFeature: Reducer {
    @Dependency(\.userService) var userService: UserService  // TCA

    struct State {
        @Injected var logger: Logger  // WeaveDI
    }
}

๐ŸŽจ Swift ๋งคํฌ๋กœ ์ง€์› (v3.2.1+)

WeaveDI๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„ ์ตœ์ ํ™”์™€ Needle ์Šคํƒ€์ผ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์œ„ํ•œ ๊ฐ•๋ ฅํ•œ Swift ๋งคํฌ๋กœ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@Component - Needle ์Šคํƒ€์ผ ์ปดํฌ๋„ŒํŠธ (10x ๋น ๋ฆ„)

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 - ์ž๋™ ์˜์กด์„ฑ ๋“ฑ๋ก

@AutoRegister(lifetime: .singleton)
class DatabaseService: DatabaseServiceProtocol {
    // ์ž๋™์œผ๋กœ UnifiedDI์— ๋“ฑ๋ก๋จ
}

@AutoRegister(lifetime: .transient)
class RequestHandler: RequestHandlerProtocol {
    // ๋งค๋ฒˆ ์ƒˆ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
}

@DIActor - Swift Concurrency ์ตœ์ ํ™”

@DIActor
public final class AutoMonitor {
    public static let shared = AutoMonitor()

    // ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ์ž๋™์œผ๋กœ ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•ด์ง
    public func onModuleRegistered<T>(_ type: T.Type) {
        // Actor ๊ฒฉ๋ฆฌ๋œ ์•ˆ์ „ํ•œ ์ž‘์—…
    }
}

@DependencyGraph - ์ปดํŒŒ์ผ ํƒ€์ž„ ๊ฒ€์ฆ

@DependencyGraph([
    UserService.self: [UserRepository.self, Logger.self],
    UserRepository.self: [DatabaseService.self],
    DatabaseService.self: [],
    Logger.self: []
])
class ApplicationDependencyGraph {
    // โœ… ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ˆœํ™˜ ์˜์กด์„ฑ ๊ฒ€์ฆ
}

์„ฑ๋Šฅ ๋น„๊ต (WeaveDI vs ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ)

ํ”„๋ ˆ์ž„์›Œํฌ ๋“ฑ๋ก ํ•ด๊ฒฐ ๋ฉ”๋ชจ๋ฆฌ ๋™์‹œ์„ฑ
Swinject ~1.2ms ~0.8ms ๋†’์Œ ์ˆ˜๋™ ๋ฝ
Needle ~0.8ms ~0.6ms ๋ณดํ†ต ์ œํ•œ์ 
WeaveDI ~0.2ms ~0.1ms ๋‚ฎ์Œ ๋„ค์ดํ‹ฐ๋ธŒ async/await

๋” ์ž์„ธํ•œ ๋งคํฌ๋กœ ์‚ฌ์šฉ๋ฒ•์€ WeaveDI ๋งคํฌ๋กœ ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๋ถ€ํŠธ์ŠคํŠธ๋žฉ(์•ฑ ์‹œ์ž‘ ์‹œ ์ดˆ๊ธฐํ™”)

import WeaveDI

// ๋™๊ธฐ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ
UnifiedDI.bootstrap { di in
    di.register { ConsoleLogger() }
    di.register { DefaultNetworking() }
}

// ๋น„๋™๊ธฐ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ
await UnifiedDI.bootstrap { di in
    let flags = await FeatureFlags.fetch()
    di.register { flags }
}

์ฝ๊ธฐ(๊ทธ๋ž˜ํ”„/ํ†ต๊ณ„/์ตœ์ ํ™” ์—ฌ๋ถ€)๋Š” UnifiedDI์˜ ๋™๊ธฐ ํ—ฌํผ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€ AutoDIOptimizer ๋ฆฌ๋”๋Š” ์Šค๋ƒ…์ƒท ๊ธฐ๋ฐ˜ ๋‚ด๋ถ€์šฉ์ด๋ฉฐ, ์™ธ๋ถ€ ์ง์ ‘ ํ˜ธ์ถœ์€ ๋น„๊ถŒ์žฅ(Deprecated)์ž…๋‹ˆ๋‹ค.

๐Ÿ“š ํ•ต์‹ฌ API

๋“ฑ๋ก API

// Core ๊ถŒ์žฅ: bootstrap ์•ˆ์—์„œ ๋“ฑ๋ก
UnifiedDI.bootstrap { di in
    di.register(ServiceProtocol.self) { ServiceImpl() }
    di.register(UserRepositoryProtocol.self) { UserRepositoryImpl() }
}

Property Wrapper

Property Wrapper ์šฉ๋„ ์˜ˆ์‹œ ์ƒํƒœ
@Injected TCA ์Šคํƒ€์ผ ์ฃผ์ž… (๊ถŒ์žฅ) @Injected(\.service) var service โœ… v3.2.0
@Dependency TCA ์Šคํƒ€์ผ ์ฃผ์ž… (๋™์ผ ์ €์žฅ์†Œ) @Dependency(\.service) var service โœ… v3.2.0
@Factory ํŒฉํ† ๋ฆฌ ํŒจํ„ด (์ƒˆ ์ธ์Šคํ„ด์Šค) @Factory var generator: Generator โœ… ์œ ์ง€
@Inject ๊ธฐ๋ณธ ์ฃผ์ž… (๋ ˆ๊ฑฐ์‹œ) @Inject var service: Service? โš ๏ธ (v3.2.0๋ถ€ํ„ฐ Deprecated)
@SafeInject ์•ˆ์ „ํ•œ ์ฃผ์ž… (๋ ˆ๊ฑฐ์‹œ) @SafeInject var api: API? โš ๏ธ (v3.2.0๋ถ€ํ„ฐ Deprecated)

๐Ÿ“– ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ: @Injected ๋ฌธ์„œ | AppDI ๊ฐ„์†Œํ™”

ํ•ด๊ฒฐ API

// ์ผ๋ฐ˜ ํ•ด๊ฒฐ
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 ๊ฐ์ง€ ๋ฐ ์ตœ์ ํ™”

// ํ•ด๊ฒฐํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ์ž๋™์œผ๋กœ 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)

ํ•ต์‹ฌ ์ตœ์ ํ™” ๊ธฐ์ˆ 

  1. TypeID + ์ธ๋ฑ์Šค ์ ‘๊ทผ: ๋”•์…”๋„ˆ๋ฆฌ โ†’ ๋ฐฐ์—ด ์Šฌ๋กฏ์œผ๋กœ O(1) ์ ‘๊ทผ
  2. ๋ฝ-ํ”„๋ฆฌ ์ฝ๊ธฐ: ์Šค๋ƒ…์ƒท ๋ฐฉ์‹์œผ๋กœ ์ฝ๊ธฐ ๊ฒฝํ•ฉ ์ œ๊ฑฐ
  3. ์ธ๋ผ์ธ ์ตœ์ ํ™”: ํ•จ์ˆ˜ ํ˜ธ์ถœ ์˜ค๋ฒ„ํ—ค๋“œ ์ถ•์†Œ
  4. ํŒฉํ† ๋ฆฌ ์ฒด์ด๋‹ ์ œ๊ฑฐ: ์ง์ ‘ ํ˜ธ์ถœ ๊ฒฝ๋กœ๋กœ ์ค‘๊ฐ„ ๋‹จ๊ณ„ ์ œ๊ฑฐ
  5. ์Šค์ฝ”ํ”„๋ณ„ ์ €์žฅ์†Œ: ์‹ฑ๊ธ€ํ†ค/์„ธ์…˜/์š”์ฒญ ์Šค์ฝ”ํ”„ ๋ถ„๋ฆฌ ์ตœ์ ํ™”

์˜ˆ์ƒ ์„ฑ๋Šฅ ํ–ฅ์ƒ

์‹œ๋‚˜๋ฆฌ์˜ค ๊ฐœ์„ ์œจ ์„ค๋ช…
๋‹จ์ผ ์Šค๋ ˆ๋“œ 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

๐Ÿ”ง Deprecated ์ฝ๊ธฐ API (๋Œ€์ฒด ๊ฒฝ๋กœ)

์•„๋ž˜ AutoDIOptimizer์˜ ์ฝ๊ธฐ์šฉ API๋Š” ๋‚ด๋ถ€ ์Šค๋ƒ…์ƒท ๊ธฐ๋ฐ˜์œผ๋กœ ์žฌ๊ตฌ์„ฑ๋˜์—ˆ์œผ๋ฉฐ, ์™ธ๋ถ€ ์‚ฌ์šฉ์€ ๋น„๊ถŒ์žฅ(Deprecated)์ž…๋‹ˆ๋‹ค. UnifiedDI์˜ ๋™๊ธฐ ํ—ฌํผ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

Deprecated (AutoDIOptimizer) Replacement
getCurrentStats() UnifiedDI.stats()
visualizeGraph() UnifiedDI.autoGraph()
getFrequentlyUsedTypes() UnifiedDI.optimizedTypes()
getDetectedCircularDependencies() UnifiedDI.circularDependencies()
isOptimized(_:) UnifiedDI.isOptimized(_:)
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_plot

matplotlib์ด ์—†์œผ๋ฉด ํ…์ŠคํŠธ ์š”์•ฝ๋งŒ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์„ค์น˜: pip install matplotlib

๐Ÿ“– ๋ฌธ์„œ ๋ฐ ํŠœํ† ๋ฆฌ์–ผ

๐Ÿ“š ๊ณต์‹ ๋ฌธ์„œ

โšก ํ•ซํŒจ์Šค ์ •์ ํ™” ํ™œ์„ฑํ™” (USE_STATIC_FACTORY)

  • ์˜๋ฏธ: ๋ฐ˜๋ณตยทํ”„๋ ˆ์ž„ ๋ฃจํ”„ ๋“ฑ ํ•ซํŒจ์Šค์—์„œ ๋Ÿฐํƒ€์ž„ ํ•ด์„์„ ์—†์•  ์ •์  ์ƒ์„ฑ/์บ์‹œ๋กœ ๋Œ€์ฒดํ•ด ๋น„์šฉ์„ 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

๐Ÿ“ ์„ฑ๋Šฅ ์ธก์ • ๊ฐ€์ด๋“œ

  • ๋ฐ˜๋“œ์‹œ 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ํšŒ ํ™•๋ณด โ†’ ์•ˆ์—์„œ๋Š” ์žฌ์‚ฌ์šฉ)

๐ŸŽฏ ํŠœํ† ๋ฆฌ์–ผ

๐ŸŽฏ ์ฃผ์š” ์ฐจ๋ณ„์ 

๐Ÿ† vs Uber Needle: ๋ชจ๋“  ์žฅ์  + ๋” ๋‚˜์€ ๊ฒฝํ—˜

ํŠน์ง• 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 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ

1. ์™„์ „ ์ž๋™ํ™”๋œ ์ตœ์ ํ™”

  • ๋ณ„๋„ ์„ค์ • ์—†์ด Actor hop ๊ฐ์ง€, ํƒ€์ž… ์•ˆ์ „์„ฑ ๊ฒ€์ฆ, ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ฐ€ ์ž๋™ ์‹คํ–‰
  • ์‹ค์‹œ๊ฐ„ ๋ถ„์„์œผ๋กœ 30์ดˆ๋งˆ๋‹ค ์ตœ์ ํ™” ์ˆ˜ํ–‰ (Needle์— ์—†๋Š” ๊ธฐ๋Šฅ)
  • ๊ฐœ๋ฐœ์ž ์นœํ™”์  ์ œ์•ˆ์œผ๋กœ ์„ฑ๋Šฅ ๊ฐœ์„ ์  ์ž๋™ ์•ˆ๋‚ด

2. Swift Concurrency ๋„ค์ดํ‹ฐ๋ธŒ (Needle ๋Œ€๋น„ ์šฐ์œ„)

  • Actor ์•ˆ์ „์„ฑ ์ž๋™ ๊ฒ€์ฆ ๋ฐ ์ตœ์ ํ™” ์ œ์•ˆ
  • async/await ์™„๋ฒฝ ์ง€์› (Needle์€ ์ œํ•œ์ )
  • Sendable ํ”„๋กœํ† ์ฝœ ์ค€์ˆ˜ ๊ฒ€์ฆ

3. ๋‹จ์ˆœํ•˜๋ฉด์„œ๋„ ๊ฐ•๋ ฅํ•œ API

  • 2๊ฐœ Property Wrapper๋งŒ์œผ๋กœ ๋ชจ๋“  ์ฃผ์ž… ํŒจํ„ด ์ปค๋ฒ„ (@Injected, @Factory)
    • ์ฐธ๊ณ : @Inject์™€ @SafeInject๋Š” v3.2.0๋ถ€ํ„ฐ Deprecated. @Injected ์‚ฌ์šฉ ๊ถŒ์žฅ
  • ํƒ€์ž… ์•ˆ์ „ํ•œ KeyPath ๊ธฐ๋ฐ˜ ๋“ฑ๋ก
  • ์ง๊ด€์ ์ธ ์กฐ๊ฑด๋ถ€ ๋“ฑ๋ก

๐Ÿ“„ ๋ผ์ด์„ ์Šค

MIT License. ์ž์„ธํ•œ ๋‚ด์šฉ์€ LICENSE ํŒŒ์ผ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๐Ÿ‘จโ€๐Ÿ’ป ๊ฐœ๋ฐœ์ž

์„œ์›์ง€ (Roy, Wonji Suh)

๐Ÿค ๊ธฐ์—ฌํ•˜๊ธฐ

WeaveDI๋ฅผ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”!

๊ธฐ์—ฌ ๋ฐฉ๋ฒ•

  1. ์ด์Šˆ ์ œ๊ธฐ: GitHub Issues์—์„œ ๋ฒ„๊ทธ ๋ฆฌํฌํŠธ๋‚˜ ๊ธฐ๋Šฅ ์š”์ฒญ
  2. Pull Request: ๊ฐœ์„ ์‚ฌํ•ญ์ด๋‚˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์„œ ๊ธฐ์—ฌ
  3. ๋ฌธ์„œ ๊ฐœ์„ : README๋‚˜ ๋ฌธ์„œ์˜ ์˜คํƒ€, ๊ฐœ์„ ์‚ฌํ•ญ ์ œ์•ˆ

๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •

git clone https://github.com/Roy-wonji/WeaveDI.git
cd WeaveDI
swift build
swift test

WeaveDI์™€ ํ•จ๊ป˜ ๋” ๋‚˜์€ Swift ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ๋งŒ๋“ค์–ด๊ฐ€์„ธ์š”! ๐Ÿš€

โญ ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด Star๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”! โญ