Skip to content

Commit 0e845ad

Browse files
committed
@LoopBinding and @EnvironmentLoop for SwiftUI.
1 parent a013754 commit 0e845ad

13 files changed

+358
-1
lines changed

Example/Root/RootView.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ struct RootView: View {
2020
CardNavigationLink(label: "Unified Store + UIKit", color: .blue) {
2121
UnifiedStoreUIKitHomeView()
2222
}
23+
24+
CardNavigationLink(label: "SwiftUI: Basic Binding", color: .orange) {
25+
SwiftUIBasicBindingHomeView()
26+
}
2327
}
2428
.navigationBarTitle("Loop Examples")
2529
.navigationBarHidden(true)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import SwiftUI
2+
import Loop
3+
4+
struct EnvironmentLoopExampleView: View {
5+
let loop: Loop<Int, Int>
6+
7+
init(loop: Loop<Int, Int>) {
8+
self.loop = loop
9+
}
10+
11+
var body: some View {
12+
EnvironmentLoopContentView()
13+
.environmentLoop(self.loop)
14+
.navigationBarTitle("@EnvironmentLoop")
15+
}
16+
}
17+
18+
private struct EnvironmentLoopContentView: View {
19+
@EnvironmentLoop<Int, Int> var state: Int
20+
21+
var body: some View {
22+
SimpleCounterView(binding: $state)
23+
}
24+
}
25+
26+
struct EnvironmentLoopExampleView_Previews: PreviewProvider {
27+
static var previews: some View {
28+
NavigationView {
29+
EnvironmentLoopExampleView(loop: simpleCounterStore)
30+
}
31+
}
32+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import SwiftUI
2+
import Loop
3+
4+
struct LoopBindingExampleView: View {
5+
@LoopBinding<Int, Int> var state: Int
6+
7+
init(state: LoopBinding<Int, Int>) {
8+
_state = state
9+
}
10+
11+
var body: some View {
12+
SimpleCounterView(binding: $state)
13+
.navigationBarTitle("@LoopBinding")
14+
}
15+
}
16+
17+
struct LoopBindingExampleView_Previews: PreviewProvider {
18+
static var previews: some View {
19+
NavigationView {
20+
LoopBindingExampleView(state: simpleCounterStore.binding)
21+
}
22+
}
23+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Loop
2+
3+
let simpleCounterStore = Loop(initial: 0, reducer: { state, event in state += event }, feedbacks: [])
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import SwiftUI
2+
import Loop
3+
4+
struct SimpleCounterView: View {
5+
@LoopBinding<Int, Int> var state: Int
6+
7+
init(binding: LoopBinding<Int, Int>) {
8+
_state = binding
9+
}
10+
11+
var body: some View {
12+
VStack {
13+
Spacer()
14+
.layoutPriority(1.0)
15+
16+
Button(
17+
action: { self.$state.send(-1) },
18+
label: { Image(systemName: "minus.circle") }
19+
)
20+
.padding()
21+
22+
Text("\(self.state)")
23+
.font(.system(.largeTitle, design: .monospaced))
24+
25+
Button(
26+
action: { self.$state.send(1) },
27+
label: { Image(systemName: "plus.circle") }
28+
)
29+
.padding()
30+
31+
Spacer()
32+
.layoutPriority(1.0)
33+
}
34+
}
35+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import SwiftUI
2+
import Loop
3+
4+
struct SwiftUIBasicBindingHomeView: View {
5+
var body: some View {
6+
ScrollView {
7+
CardNavigationLink(label: "@LoopBinding", color: .orange) {
8+
LoopBindingExampleView(state: simpleCounterStore.binding)
9+
}
10+
11+
CardNavigationLink(label: "@EnvironmentLoop", color: .orange) {
12+
EnvironmentLoopExampleView(loop: simpleCounterStore)
13+
}
14+
}
15+
}
16+
}

Loop.xcodeproj/project.pbxproj

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838
5B017D2C246F33DE00400BFE /* ArrayCollectionViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B017D2B246F33DE00400BFE /* ArrayCollectionViewAdapter.swift */; };
3939
5B017D30246F344500400BFE /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B017D2F246F344500400BFE /* CardView.swift */; };
4040
5B017D32246F466600400BFE /* RACHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B017D31246F466600400BFE /* RACHeaderView.swift */; };
41+
5B8F920C24731F2800C1C90E /* LoopBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F920B24731F2800C1C90E /* LoopBinding.swift */; };
42+
5B8F920D24731F2800C1C90E /* LoopBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F920B24731F2800C1C90E /* LoopBinding.swift */; };
43+
5B8F920E24731F2800C1C90E /* LoopBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F920B24731F2800C1C90E /* LoopBinding.swift */; };
44+
5B8F92102473242900C1C90E /* SwiftUISubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F920F2473242900C1C90E /* SwiftUISubscription.swift */; };
45+
5B8F92112473242900C1C90E /* SwiftUISubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F920F2473242900C1C90E /* SwiftUISubscription.swift */; };
46+
5B8F92122473242900C1C90E /* SwiftUISubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F920F2473242900C1C90E /* SwiftUISubscription.swift */; };
47+
5B8F922124732C4600C1C90E /* SwiftUIBasicBindingHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F922024732C4600C1C90E /* SwiftUIBasicBindingHomeView.swift */; };
48+
5B8F922324732C9500C1C90E /* LoopBindingExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F922224732C9500C1C90E /* LoopBindingExampleView.swift */; };
49+
5B8F922724732E1700C1C90E /* SimpleCounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F922624732E1700C1C90E /* SimpleCounterView.swift */; };
4150
5BC88F842469CBA300394C63 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BC88F832469CBA300394C63 /* Nimble.framework */; };
4251
5BC88F862469CBAB00394C63 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BC88F852469CBAB00394C63 /* Nimble.framework */; };
4352
5BC88F88246AFC5900394C63 /* ReactiveSwift+EnqueueTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC88F87246AFC5900394C63 /* ReactiveSwift+EnqueueTo.swift */; };
@@ -55,6 +64,14 @@
5564
5BC88F9C246B1CDE00394C63 /* SignalProducer+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC88F9B246B1CDE00394C63 /* SignalProducer+Loop.swift */; };
5665
5BC88F9D246B1CDE00394C63 /* SignalProducer+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC88F9B246B1CDE00394C63 /* SignalProducer+Loop.swift */; };
5766
5BC88F9E246B1CDE00394C63 /* SignalProducer+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC88F9B246B1CDE00394C63 /* SignalProducer+Loop.swift */; };
67+
5BDEDA3B2473357A00A13013 /* EnvironmentLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F92132473250E00C1C90E /* EnvironmentLoop.swift */; };
68+
5BDEDA3C2473357A00A13013 /* EnvironmentLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F92132473250E00C1C90E /* EnvironmentLoop.swift */; };
69+
5BDEDA3D2473357B00A13013 /* EnvironmentLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F92132473250E00C1C90E /* EnvironmentLoop.swift */; };
70+
5BDEDA3E2473359C00A13013 /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F921B247325C300C1C90E /* EnvironmentValues.swift */; };
71+
5BDEDA3F2473359D00A13013 /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F921B247325C300C1C90E /* EnvironmentValues.swift */; };
72+
5BDEDA402473359D00A13013 /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F921B247325C300C1C90E /* EnvironmentValues.swift */; };
73+
5BDEDA41247335C700A13013 /* EnvironmentLoopExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F922424732CA000C1C90E /* EnvironmentLoopExampleView.swift */; };
74+
5BDEDA432473377A00A13013 /* SimpleCounterStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDEDA422473377A00A13013 /* SimpleCounterStore.swift */; };
5875
656A9C9323D0813500EFB2F8 /* FeedbackLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656A9C9223D0813500EFB2F8 /* FeedbackLoop.swift */; };
5976
656A9C9423D0813500EFB2F8 /* FeedbackLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656A9C9223D0813500EFB2F8 /* FeedbackLoop.swift */; };
6077
656A9C9523D0813500EFB2F8 /* FeedbackLoop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656A9C9223D0813500EFB2F8 /* FeedbackLoop.swift */; };
@@ -203,13 +220,22 @@
203220
5B017D2B246F33DE00400BFE /* ArrayCollectionViewAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayCollectionViewAdapter.swift; sourceTree = "<group>"; };
204221
5B017D2F246F344500400BFE /* CardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = "<group>"; };
205222
5B017D31246F466600400BFE /* RACHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RACHeaderView.swift; sourceTree = "<group>"; };
223+
5B8F920B24731F2800C1C90E /* LoopBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopBinding.swift; sourceTree = "<group>"; };
224+
5B8F920F2473242900C1C90E /* SwiftUISubscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUISubscription.swift; sourceTree = "<group>"; };
225+
5B8F92132473250E00C1C90E /* EnvironmentLoop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentLoop.swift; sourceTree = "<group>"; };
226+
5B8F921B247325C300C1C90E /* EnvironmentValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; };
227+
5B8F922024732C4600C1C90E /* SwiftUIBasicBindingHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIBasicBindingHomeView.swift; sourceTree = "<group>"; };
228+
5B8F922224732C9500C1C90E /* LoopBindingExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopBindingExampleView.swift; sourceTree = "<group>"; };
229+
5B8F922424732CA000C1C90E /* EnvironmentLoopExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentLoopExampleView.swift; sourceTree = "<group>"; };
230+
5B8F922624732E1700C1C90E /* SimpleCounterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleCounterView.swift; sourceTree = "<group>"; };
206231
5BC88F832469CBA300394C63 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; };
207232
5BC88F852469CBAB00394C63 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; };
208233
5BC88F87246AFC5900394C63 /* ReactiveSwift+EnqueueTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReactiveSwift+EnqueueTo.swift"; sourceTree = "<group>"; };
209234
5BC88F8D246B11DE00394C63 /* LoopBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopBox.swift; sourceTree = "<group>"; };
210235
5BC88F91246B17B200394C63 /* Context.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = "<group>"; };
211236
5BC88F97246B191200394C63 /* Loop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loop.swift; sourceTree = "<group>"; };
212237
5BC88F9B246B1CDE00394C63 /* SignalProducer+Loop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignalProducer+Loop.swift"; sourceTree = "<group>"; };
238+
5BDEDA422473377A00A13013 /* SimpleCounterStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleCounterStore.swift; sourceTree = "<group>"; };
213239
656A9C9223D0813500EFB2F8 /* FeedbackLoop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackLoop.swift; sourceTree = "<group>"; };
214240
656A9C9623D0826100EFB2F8 /* FeedbackEventConsumer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackEventConsumer.swift; sourceTree = "<group>"; };
215241
65761B2523CF20EF004D5506 /* Floodgate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Floodgate.swift; sourceTree = "<group>"; };
@@ -341,6 +367,7 @@
341367
25E1D21F1F5493D000D90192 /* Example */ = {
342368
isa = PBXGroup;
343369
children = (
370+
5B8F921F24732C0300C1C90E /* SwiftUIBasicBindingExample */,
344371
585CD886239E904E004BE9CC /* UnifiedStoreUIKitExample */,
345372
5B017D2D246F340900400BFE /* Root */,
346373
5B017D21246F2CBF00400BFE /* Misc */,
@@ -434,9 +461,33 @@
434461
path = SwiftUI;
435462
sourceTree = "<group>";
436463
};
464+
5B8F920A24731F1800C1C90E /* SwiftUI */ = {
465+
isa = PBXGroup;
466+
children = (
467+
5B8F920B24731F2800C1C90E /* LoopBinding.swift */,
468+
5B8F92132473250E00C1C90E /* EnvironmentLoop.swift */,
469+
5B8F921B247325C300C1C90E /* EnvironmentValues.swift */,
470+
5B8F920F2473242900C1C90E /* SwiftUISubscription.swift */,
471+
);
472+
path = SwiftUI;
473+
sourceTree = "<group>";
474+
};
475+
5B8F921F24732C0300C1C90E /* SwiftUIBasicBindingExample */ = {
476+
isa = PBXGroup;
477+
children = (
478+
5B8F922024732C4600C1C90E /* SwiftUIBasicBindingHomeView.swift */,
479+
5B8F922224732C9500C1C90E /* LoopBindingExampleView.swift */,
480+
5B8F922424732CA000C1C90E /* EnvironmentLoopExampleView.swift */,
481+
5B8F922624732E1700C1C90E /* SimpleCounterView.swift */,
482+
5BDEDA422473377A00A13013 /* SimpleCounterStore.swift */,
483+
);
484+
path = SwiftUIBasicBindingExample;
485+
sourceTree = "<group>";
486+
};
437487
5BC88F95246B188300394C63 /* Public */ = {
438488
isa = PBXGroup;
439489
children = (
490+
5B8F920A24731F1800C1C90E /* SwiftUI */,
440491
5BC88F97246B191200394C63 /* Loop.swift */,
441492
5BC88F9B246B1CDE00394C63 /* SignalProducer+Loop.swift */,
442493
656A9C9223D0813500EFB2F8 /* FeedbackLoop.swift */,
@@ -759,6 +810,7 @@
759810
buildActionMask = 2147483647;
760811
files = (
761812
A9509BE4551098F4A5503820 /* Feedback.swift in Sources */,
813+
5B8F920C24731F2800C1C90E /* LoopBinding.swift in Sources */,
762814
A950943401765BB90FA846B2 /* SignalProducer+System.swift in Sources */,
763815
65761B2E23CF4CA2004D5506 /* NSLock+Extensions.swift in Sources */,
764816
5BC88F9C246B1CDE00394C63 /* SignalProducer+Loop.swift in Sources */,
@@ -767,10 +819,13 @@
767819
9AD5D42D1F97375E00E6AE5A /* Property+System.swift in Sources */,
768820
5BC88F88246AFC5900394C63 /* ReactiveSwift+EnqueueTo.swift in Sources */,
769821
656A9C9323D0813500EFB2F8 /* FeedbackLoop.swift in Sources */,
822+
5B8F92102473242900C1C90E /* SwiftUISubscription.swift in Sources */,
823+
5BDEDA3E2473359C00A13013 /* EnvironmentValues.swift in Sources */,
770824
656A9C9723D0826100EFB2F8 /* FeedbackEventConsumer.swift in Sources */,
771825
5BC88F8E246B11DE00394C63 /* LoopBox.swift in Sources */,
772826
65761B2623CF20EF004D5506 /* Floodgate.swift in Sources */,
773827
5BC88F98246B191200394C63 /* Loop.swift in Sources */,
828+
5BDEDA3B2473357A00A13013 /* EnvironmentLoop.swift in Sources */,
774829
);
775830
runOnlyForDeploymentPostprocessing = 0;
776831
};
@@ -781,6 +836,9 @@
781836
5B017D27246F2EDB00400BFE /* UnifiedStoreUIKitHomeView.swift in Sources */,
782837
5B017D29246F2F7E00400BFE /* ContentViewController.swift in Sources */,
783838
585CD88A239E9077004BE9CC /* Counter.swift in Sources */,
839+
5BDEDA432473377A00A13013 /* SimpleCounterStore.swift in Sources */,
840+
5B8F922324732C9500C1C90E /* LoopBindingExampleView.swift in Sources */,
841+
5BDEDA41247335C700A13013 /* EnvironmentLoopExampleView.swift in Sources */,
784842
5810F03A239EBEA100708F62 /* UnifiedStore.swift in Sources */,
785843
5810F038239EB5A700708F62 /* MovieCell.swift in Sources */,
786844
5B017D23246F2CD600400BFE /* RootView.swift in Sources */,
@@ -793,6 +851,8 @@
793851
5810F03F239FAB0200708F62 /* ColorPickerView.swift in Sources */,
794852
5810F03D239FA9F200708F62 /* ColorPicker.swift in Sources */,
795853
25E1D2211F5493D000D90192 /* AppDelegate.swift in Sources */,
854+
5B8F922124732C4600C1C90E /* SwiftUIBasicBindingHomeView.swift in Sources */,
855+
5B8F922724732E1700C1C90E /* SimpleCounterView.swift in Sources */,
796856
585CD88C239E90EB004BE9CC /* CounterView.swift in Sources */,
797857
5B017D30246F344500400BFE /* CardView.swift in Sources */,
798858
5B017D2C246F33DE00400BFE /* ArrayCollectionViewAdapter.swift in Sources */,
@@ -804,6 +864,7 @@
804864
buildActionMask = 2147483647;
805865
files = (
806866
65F8C260218371A800924657 /* Feedback.swift in Sources */,
867+
5B8F920D24731F2800C1C90E /* LoopBinding.swift in Sources */,
807868
65F8C261218371A800924657 /* SignalProducer+System.swift in Sources */,
808869
65761B2F23CF4CA2004D5506 /* NSLock+Extensions.swift in Sources */,
809870
5BC88F9D246B1CDE00394C63 /* SignalProducer+Loop.swift in Sources */,
@@ -812,10 +873,13 @@
812873
65F8C262218371A800924657 /* Property+System.swift in Sources */,
813874
5BC88F89246AFC5900394C63 /* ReactiveSwift+EnqueueTo.swift in Sources */,
814875
656A9C9423D0813500EFB2F8 /* FeedbackLoop.swift in Sources */,
876+
5B8F92112473242900C1C90E /* SwiftUISubscription.swift in Sources */,
877+
5BDEDA3F2473359D00A13013 /* EnvironmentValues.swift in Sources */,
815878
656A9C9823D0826100EFB2F8 /* FeedbackEventConsumer.swift in Sources */,
816879
5BC88F8F246B11DE00394C63 /* LoopBox.swift in Sources */,
817880
65761B2723CF20EF004D5506 /* Floodgate.swift in Sources */,
818881
5BC88F99246B191200394C63 /* Loop.swift in Sources */,
882+
5BDEDA3C2473357A00A13013 /* EnvironmentLoop.swift in Sources */,
819883
);
820884
runOnlyForDeploymentPostprocessing = 0;
821885
};
@@ -824,6 +888,7 @@
824888
buildActionMask = 2147483647;
825889
files = (
826890
65F8C26F218371AC00924657 /* Feedback.swift in Sources */,
891+
5B8F920E24731F2800C1C90E /* LoopBinding.swift in Sources */,
827892
65F8C270218371AC00924657 /* SignalProducer+System.swift in Sources */,
828893
65761B3023CF4CA2004D5506 /* NSLock+Extensions.swift in Sources */,
829894
5BC88F9E246B1CDE00394C63 /* SignalProducer+Loop.swift in Sources */,
@@ -832,10 +897,13 @@
832897
65F8C271218371AC00924657 /* Property+System.swift in Sources */,
833898
5BC88F8A246AFC5900394C63 /* ReactiveSwift+EnqueueTo.swift in Sources */,
834899
656A9C9523D0813500EFB2F8 /* FeedbackLoop.swift in Sources */,
900+
5B8F92122473242900C1C90E /* SwiftUISubscription.swift in Sources */,
901+
5BDEDA402473359D00A13013 /* EnvironmentValues.swift in Sources */,
835902
656A9C9923D0826100EFB2F8 /* FeedbackEventConsumer.swift in Sources */,
836903
5BC88F90246B11DE00394C63 /* LoopBox.swift in Sources */,
837904
65761B2823CF20EF004D5506 /* Floodgate.swift in Sources */,
838905
5BC88F9A246B191200394C63 /* Loop.swift in Sources */,
906+
5BDEDA3D2473357B00A13013 /* EnvironmentLoop.swift in Sources */,
839907
);
840908
runOnlyForDeploymentPostprocessing = 0;
841909
};

Loop/LoopBox.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ internal class ScopedLoopBox<RootState, RootEvent, ScopedState, ScopedEvent>: Lo
99
root.lifetime
1010
}
1111

12+
/// Loop Internal SPI
13+
override var _current: ScopedState {
14+
root._current[keyPath: value]
15+
}
16+
1217
private let root: LoopBoxBase<RootState, RootEvent>
1318
private let value: KeyPath<RootState, ScopedState>
1419
private let eventTransform: (ScopedEvent) -> RootEvent
@@ -44,6 +49,11 @@ internal class RootLoopBox<State, Event>: LoopBoxBase<State, Event> {
4449
_lifetime
4550
}
4651

52+
/// Loop Internal SPI
53+
override var _current: State {
54+
floodgate.withValue { state, _ in state }
55+
}
56+
4757
let floodgate: Floodgate<State, Event>
4858
private let _lifetime: Lifetime
4959
private let token: Lifetime.Token
@@ -89,6 +99,9 @@ internal class RootLoopBox<State, Event>: LoopBoxBase<State, Event> {
8999
}
90100

91101
internal class LoopBoxBase<State, Event> {
102+
/// Loop Internal SPI
103+
var _current: State { subclassMustImplement() }
104+
92105
var lifetime: Lifetime { subclassMustImplement() }
93106
var producer: SignalProducer<State, Never> { subclassMustImplement() }
94107

Loop/Public/Loop.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ public final class Loop<State, Event> {
1919
}
2020
}
2121

22-
private let box: LoopBoxBase<State, Event>
22+
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
23+
public var binding: LoopBinding<State, Event> {
24+
LoopBinding(self)
25+
}
26+
27+
internal let box: LoopBoxBase<State, Event>
2328

2429
private init(box: LoopBoxBase<State, Event>) {
2530
self.box = box

0 commit comments

Comments
 (0)