Skip to content

Commit 5c597f3

Browse files
committed
Improve support Swift Concurrency - fix support detect MainActor register with modificators.
1 parent 8815c08 commit 5c597f3

File tree

4 files changed

+137
-4
lines changed

4 files changed

+137
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 5.0.2
2+
* Improve support Swift Concurrency - fix support detect MainActor register with modificators. e.g.:
3+
`container.register(MyMainActorClass.init) { arg($0) }`
4+
15
# 5.0.1
26
* Improve support Swift Concurrency - fix support detect MainActor classes for register methods initialize.
37

Sources/Core/API/AutoResolve/DIContainer.RegModify.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,36 @@ extension DIContainer {
3838
modificator: @escaping (M0, M1) -> (P0, P1)) -> DIComponentBuilder<Impl> {
3939
return register(file, line, MethodMaker.eachMake(by: closure, modificator: modificator))
4040
}
41+
42+
/// Declaring a new component with initial and modificator one argument.
43+
/// Using:
44+
/// ```
45+
/// container.register(YourClass.init) { arg($0) }
46+
/// ```
47+
///
48+
/// - Parameter closure: initial method. Must return type declared at registration.
49+
/// - Parameter modificator: Need for support set arg / many / tag on first initial argument.
50+
/// - Returns: component builder, to configure the component.
51+
@discardableResult
52+
public func register<Impl,P0,each P,M0>(file: String = #file, line: Int = #line,
53+
_ closure: @escaping @MainActor (P0, repeat each P) -> Impl,
54+
modificator: @escaping (M0) -> P0) -> DIComponentBuilder<Impl> where Impl: Sendable {
55+
return register(file, line, MethodMaker.eachMakeMainActor(by: closure, modificator: modificator))
56+
}
57+
58+
/// Declaring a new component with initial and modificator one argument.
59+
/// Using:
60+
/// ```
61+
/// container.register(YourClass.init) { (arg($0), many($1)) }
62+
/// ```
63+
///
64+
/// - Parameter closure: initial method. Must return type declared at registration.
65+
/// - Parameter modificator: Need for support set arg / many / tag on first and second initial argument.
66+
/// - Returns: component builder, to configure the component.
67+
@discardableResult
68+
public func register<Impl,P0,P1,each P,M0,M1>(file: String = #file, line: Int = #line,
69+
_ closure: @escaping @MainActor (P0, P1, repeat each P) -> Impl,
70+
modificator: @escaping (M0, M1) -> (P0, P1)) -> DIComponentBuilder<Impl> where Impl: Sendable {
71+
return register(file, line, MethodMaker.eachMakeMainActor(by: closure, modificator: modificator))
72+
}
4173
}

Sources/Core/Internal/MethodMaker.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,55 @@ extension MethodMaker {
115115
}
116116
}
117117
}
118+
119+
static func eachMakeMainActor<P0, each P, M0, R>(
120+
by f: @escaping @MainActor (P0, repeat each P) -> R,
121+
modificator: @escaping (M0) -> P0) -> MethodSignature where R: Sendable
122+
{
123+
let types = EachTypes()
124+
types.append(M0.self)
125+
repeat types.append((each P).self)
126+
127+
return MethodSignature(types.result, nil) { params in
128+
let maker = EachMaker(params: params)
129+
let modifyResult = modificator(maker.make())
130+
if Thread.isMainThread {
131+
return MainActor.assumeIsolated {
132+
f(modifyResult, repeat maker.make() as each P)
133+
}
134+
} else {
135+
return DispatchQueue.main.sync {
136+
MainActor.assumeIsolated {
137+
f(modifyResult, repeat maker.make() as each P)
138+
}
139+
}
140+
}
141+
}
142+
}
143+
144+
static func eachMakeMainActor<P0, P1, each P, M0, M1, R>(
145+
by f: @escaping @MainActor (P0, P1, repeat each P) -> R,
146+
modificator: @escaping (M0, M1) -> (P0, P1)) -> MethodSignature where R: Sendable
147+
{
148+
let types = EachTypes()
149+
types.append(M0.self)
150+
types.append(M1.self)
151+
repeat types.append((each P).self)
152+
153+
return MethodSignature(types.result, nil) { params in
154+
let maker = EachMaker(params: params)
155+
let modifyResult = modificator(maker.make(), maker.make())
156+
if Thread.isMainThread {
157+
return MainActor.assumeIsolated {
158+
return f(modifyResult.0, modifyResult.1, repeat maker.make() as each P)
159+
}
160+
} else {
161+
return DispatchQueue.main.sync {
162+
MainActor.assumeIsolated {
163+
return f(modifyResult.0, modifyResult.1, repeat maker.make() as each P)
164+
}
165+
}
166+
}
167+
}
168+
}
118169
}

Tests/DITranquillityTests_ResolveByInit.swift

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,34 @@ private final class TestMainActor {
3333
}
3434
}
3535

36+
@MainActor
37+
private final class TestMainActorArgument {
38+
let str: String = "bar"
39+
let arg: Int
40+
let other: TestOtherMainActor
41+
init(arg: Int, other: TestOtherMainActor) {
42+
self.arg = arg
43+
self.other = other
44+
assert(Thread.isMainThread)
45+
MainActor.assertIsolated()
46+
}
47+
}
48+
49+
@MainActor
50+
private final class TestMainActorArgument2 {
51+
let str: String = "bar"
52+
let arg1: Int
53+
let arg2: String
54+
let other: TestOtherMainActor
55+
init(arg1: Int, arg2: String, other: TestOtherMainActor) {
56+
self.arg1 = arg1
57+
self.arg2 = arg2
58+
self.other = other
59+
assert(Thread.isMainThread)
60+
MainActor.assertIsolated()
61+
}
62+
}
63+
3664
private final class TestActorClassInjected: Sendable {
3765
}
3866

@@ -107,35 +135,53 @@ class DITranquillityTests_ResolveByInit: XCTestCase {
107135

108136
container.register(TestOtherMainActor.init)
109137
container.register(TestMainActor.init)
138+
container.register(TestMainActorArgument.init) { arg($0) }
139+
container.register(TestMainActorArgument2.init) { (arg($0), arg($1)) }
110140

111141
let m1: TestOtherMainActor = container.resolve()
112142
let m2: TestMainActor = container.resolve()
143+
let m3: TestMainActorArgument = container.resolve(args: 10)
144+
let m4: TestMainActorArgument2 = container.resolve(args: 100, "a100")
113145

114146
XCTAssert(m1.str == "foo")
115147
XCTAssert(m2.str == "bar")
148+
XCTAssert(m3.arg == 10)
149+
XCTAssert(m4.arg1 == 100 && m4.arg2 == "a100")
116150

117151
DispatchQueue.global(qos: DispatchQoS.QoSClass.userInteractive).async {
118-
let m1InThread: TestOtherMainActor = container.resolve()
119-
let m2InThread: TestMainActor = container.resolve()
152+
let m1: TestOtherMainActor = container.resolve()
153+
let m2: TestMainActor = container.resolve()
154+
let m3: TestMainActorArgument = container.resolve(args: 20)
155+
let m4: TestMainActorArgument2 = container.resolve(args: 200, "a200")
120156

121-
XCTAssert(m1InThread.str == "foo")
122-
XCTAssert(m2InThread.str == "bar")
157+
XCTAssert(m1.str == "foo")
158+
XCTAssert(m2.str == "bar")
159+
XCTAssert(m3.arg == 20)
160+
XCTAssert(m4.arg1 == 200 && m4.arg2 == "a200")
123161
}
124162

125163
Task { @MainActor in
126164
let m1: TestOtherMainActor = container.resolve()
127165
let m2: TestMainActor = container.resolve()
166+
let m3: TestMainActorArgument = container.resolve(args: 30)
167+
let m4: TestMainActorArgument2 = container.resolve(args: 300, "a300")
128168

129169
XCTAssert(m1.str == "foo")
130170
XCTAssert(m2.str == "bar")
171+
XCTAssert(m3.arg == 30)
172+
XCTAssert(m4.arg1 == 300 && m4.arg2 == "a300")
131173
}
132174

133175
Task { @MyGlobalActor in
134176
let m1: TestOtherMainActor = container.resolve()
135177
let m2: TestMainActor = container.resolve()
178+
let m3: TestMainActorArgument = container.resolve(args: 40)
179+
let m4: TestMainActorArgument2 = container.resolve(args: 400, "a400")
136180

137181
XCTAssert(m1.str == "foo")
138182
XCTAssert(m2.str == "bar")
183+
XCTAssert(m3.arg == 40)
184+
XCTAssert(m4.arg1 == 400 && m4.arg2 == "a400")
139185
}
140186
}
141187

0 commit comments

Comments
 (0)