Skip to content

Generic Container with support for TargetResolver #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Example/KnitExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -429,7 +429,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -450,7 +450,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.cashapp.KnitExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -468,7 +468,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.cashapp.KnitExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
4 changes: 2 additions & 2 deletions Example/KnitExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ struct ContentView: View {
}

struct ContentView_Previews: PreviewProvider {
static let assembler = ScopedModuleAssembler<Resolver>([KnitExampleAssembly()])
static var previews: some View {
let resolver = ModuleAssembler([KnitExampleAssembly()]).resolver
return ContentView(resolver: resolver)
return ContentView(resolver: assembler.resolver)
}
}
7 changes: 5 additions & 2 deletions Example/KnitExample/KnitExampleApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import Knit
@main
struct KnitExampleApp: App {

let resolver: Resolver
let assembler: ScopedModuleAssembler<Resolver>
var resolver: Resolver { assembler.resolver }

@MainActor
init() {
resolver = ModuleAssembler([KnitExampleAssembly()]).resolver
assembler = ScopedModuleAssembler<Resolver>(
[KnitExampleAssembly()]
)
}

var body: some Scene {
Expand Down
4 changes: 1 addition & 3 deletions Example/KnitExample/KnitExampleAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ final class KnitExampleAssembly: ModuleAssembly {

static var dependencies: [any ModuleAssembly.Type] { [] }

func assemble(container: Container) {
container.addBehavior(ServiceCollector())

func assemble(container: Container<TargetResolver>) {
container.register(ExampleService.self) { ExampleService.make(resolver: $0) }

// @knit alias("example")
Expand Down
2 changes: 1 addition & 1 deletion Example/KnitExample/KnitExampleUserAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class KnitExampleUserAssembly: ModuleAssembly {

static var dependencies: [any ModuleAssembly.Type] { [] }

func assemble(container: Container) {
func assemble(container: Container<TargetResolver>) {
container.register(UserService.self) { _ in UserService() }
}
}
Expand Down
8 changes: 6 additions & 2 deletions Example/KnitExampleTests/TestModuleAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import Knit
extension KnitExampleAssembly {
@MainActor
static func makeAssemblerForTests() -> ModuleAssembler {
ModuleAssembler([KnitExampleAssembly()])
ModuleAssembler(
[KnitExampleAssembly()]
)
}

static func makeArgumentsForTests() -> KnitExampleRegistrationTestArguments {
Expand All @@ -26,6 +28,8 @@ extension KnitExampleAssembly {
extension KnitExampleUserAssembly {
@MainActor
static func makeAssemblerForTests() -> ModuleAssembler {
ModuleAssembler([KnitExampleUserAssembly(), KnitExampleAssembly()])
ModuleAssembler(
[KnitExampleUserAssembly(), KnitExampleAssembly()]
)
}
}
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let package = Package(
name: "Knit",
platforms: [
.macOS(.v14),
.iOS(.v15),
.iOS(.v16),
],
products: [
.library(name: "Knit", targets: ["Knit"]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

import Swinject

// This code should move into the Swinject library.
// There is an open pull request to make this change https://github.com/Swinject/Swinject/pull/570
// MARK: - MainActor Registration Methods

// MARK: - MainActor registration
extension Container {
extension Knit.Container {

/// Adds a registration for the specified service with the factory closure to specify how the service is
/// resolved with dependencies which must be resolved on the main actor.
Expand All @@ -27,18 +25,20 @@ extension Container {
public func register<Service>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { r in
MainActor.assumeIsolated {
return mainActorFactory(r)
return _unwrappedSwinjectContainer.register(serviceType, name: name) { r in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver)
}
}
}
}

// MARK: - MainActor registration with Arguments
extension Container {
// MARK: - MainActor Registration Methods with Arguments

extension Knit.Container {
/// Adds a registration for the specified service with the factory closure to specify how the service is
/// resolved with dependencies which must be resolved on the main actor.
///
Expand All @@ -56,10 +56,11 @@ extension Container {
public func register<Service, Arg1>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1)
}
}
Expand All @@ -82,10 +83,11 @@ extension Container {
public func register<Service, Arg1, Arg2>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2)
}
}
Expand All @@ -108,10 +110,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3)
}
}
Expand All @@ -134,10 +137,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3, Arg4>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3, Arg4) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3, Arg4) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3, arg4)
}
}
Expand All @@ -160,10 +164,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3, Arg4, Arg5>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3, Arg4, Arg5) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3, Arg4, Arg5) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3, arg4, arg5)
}
}
Expand All @@ -186,10 +191,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3, arg4, arg5, arg6)
}
}
Expand All @@ -212,10 +218,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6, arg7: Arg7) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6, arg7: Arg7) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
}
Expand All @@ -238,10 +245,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6, arg7: Arg7, arg8: Arg8) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6, arg7: Arg7, arg8: Arg8) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
}
}
Expand All @@ -264,10 +272,11 @@ extension Container {
public func register<Service, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9>(
_ serviceType: Service.Type,
name: String? = nil,
mainActorFactory: @escaping @MainActor (Resolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9) -> Service
mainActorFactory: @escaping @MainActor (TargetResolver, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9) -> Service
) -> ServiceEntry<Service> {
return register(serviceType, name: name) { (resolver: Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6, arg7: Arg7, arg8: Arg8, arg9: Arg9) in
MainActor.assumeIsolated {
return _unwrappedSwinjectContainer.register(serviceType, name: name) { (r: Swinject.Resolver, arg1: Arg1, arg2: Arg2, arg3: Arg3, arg4: Arg4, arg5: Arg5, arg6: Arg6, arg7: Arg7, arg8: Arg8, arg9: Arg9) in
let resolver = r.resolve(Container<TargetResolver>.self)!.resolver
return MainActor.assumeIsolated {
return mainActorFactory(resolver, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
}
}
Expand Down
Loading