@@ -3,6 +3,95 @@ import Combine
33import SwiftUI
44import XCTestDynamicOverlay
55
6+ #if DEBUG
7+ import os
8+ #endif
9+
10+ // NB: Deprecated after 0.31.0:
11+
12+ extension Reducer {
13+ @available (
14+ * ,
15+ deprecated,
16+ message: " 'pullback' no longer takes a 'breakpointOnNil' argument "
17+ )
18+ public func pullback< GlobalState, GlobalAction, GlobalEnvironment> (
19+ state toLocalState: CasePath < GlobalState , State > ,
20+ action toLocalAction: CasePath < GlobalAction , Action > ,
21+ environment toLocalEnvironment: @escaping ( GlobalEnvironment ) -> Environment ,
22+ breakpointOnNil: Bool ,
23+ file: StaticString = #fileID,
24+ line: UInt = #line
25+ ) -> Reducer < GlobalState , GlobalAction , GlobalEnvironment > {
26+ self . pullback (
27+ state: toLocalState,
28+ action: toLocalAction,
29+ environment: toLocalEnvironment,
30+ file: file,
31+ line: line
32+ )
33+ }
34+
35+ @available (
36+ * ,
37+ deprecated,
38+ message: " 'optional' no longer takes a 'breakpointOnNil' argument "
39+ )
40+ public func optional(
41+ breakpointOnNil: Bool ,
42+ file: StaticString = #fileID,
43+ line: UInt = #line
44+ ) -> Reducer <
45+ State ? , Action , Environment
46+ > {
47+ self . optional ( file: file, line: line)
48+ }
49+
50+ @available (
51+ * ,
52+ deprecated,
53+ message: " 'forEach' no longer takes a 'breakpointOnNil' argument "
54+ )
55+ public func forEach< GlobalState, GlobalAction, GlobalEnvironment, ID> (
56+ state toLocalState: WritableKeyPath < GlobalState , IdentifiedArray < ID , State > > ,
57+ action toLocalAction: CasePath < GlobalAction , ( ID , Action ) > ,
58+ environment toLocalEnvironment: @escaping ( GlobalEnvironment ) -> Environment ,
59+ breakpointOnNil: Bool ,
60+ file: StaticString = #fileID,
61+ line: UInt = #line
62+ ) -> Reducer < GlobalState , GlobalAction , GlobalEnvironment > {
63+ self . forEach (
64+ state: toLocalState,
65+ action: toLocalAction,
66+ environment: toLocalEnvironment,
67+ file: file,
68+ line: line
69+ )
70+ }
71+
72+ @available (
73+ * ,
74+ deprecated,
75+ message: " 'forEach' no longer takes a 'breakpointOnNil' argument "
76+ )
77+ public func forEach< GlobalState, GlobalAction, GlobalEnvironment, Key> (
78+ state toLocalState: WritableKeyPath < GlobalState , [ Key : State ] > ,
79+ action toLocalAction: CasePath < GlobalAction , ( Key , Action ) > ,
80+ environment toLocalEnvironment: @escaping ( GlobalEnvironment ) -> Environment ,
81+ breakpointOnNil: Bool ,
82+ file: StaticString = #fileID,
83+ line: UInt = #line
84+ ) -> Reducer < GlobalState , GlobalAction , GlobalEnvironment > {
85+ self . forEach (
86+ state: toLocalState,
87+ action: toLocalAction,
88+ environment: toLocalEnvironment,
89+ file: file,
90+ line: line
91+ )
92+ }
93+ }
94+
695// NB: Deprecated after 0.29.0:
796
897#if DEBUG
@@ -458,36 +547,44 @@ extension Reducer {
458547 return . none
459548 }
460549 if index >= globalState [ keyPath: toLocalState] . endIndex {
461- if breakpointOnNil {
462- breakpoint (
550+ #if DEBUG
551+ os_log (
552+ . fault, dso: rw. dso, log: rw. log,
463553 """
464- ---
465- Warning: Reducer.forEach@ \( file) : \( line)
554+ A " forEach " reducer at " %@:%d " received an action when state contained no element at \
555+ that index. …
556+
557+ Action:
558+ %@
559+ Index:
560+ %d
466561
467- " \( debugCaseOutput ( localAction) ) " was received by a " forEach " reducer at index \
468- \( index) when its state contained no element at this index. This is generally \
469- considered an application logic error, and can happen for a few reasons:
562+ This is generally considered an application logic error, and can happen for a few \
563+ reasons:
470564
471- * This " forEach " reducer was combined with or run from another reducer that removed \
565+ • This " forEach " reducer was combined with or run from another reducer that removed \
472566 the element at this index when it handled this action. To fix this make sure that \
473567 this " forEach " reducer is run before any other reducers that can move or remove \
474568 elements from state. This ensures that " forEach " reducers can handle their actions \
475569 for the element at the intended index.
476570
477- * An in-flight effect emitted this action while state contained no element at this \
571+ • An in-flight effect emitted this action while state contained no element at this \
478572 index. While it may be perfectly reasonable to ignore this action, you may want to \
479573 cancel the associated effect when moving or removing an element. If your " forEach " \
480574 reducer returns any long-living effects, you should use the identifier-based \
481575 " forEach " instead.
482576
483- * This action was sent to the store while its state contained no element at this \
577+ • This action was sent to the store while its state contained no element at this \
484578 index. To fix this make sure that actions for this reducer can only be sent to a \
485579 view store when its state contains an element at this index. In SwiftUI \
486580 applications, use " ForEachStore " .
487- ---
488- """
581+ """ ,
582+ " \( file) " ,
583+ line,
584+ debugCaseOutput ( localAction) ,
585+ index
489586 )
490- }
587+ #endif
491588 return . none
492589 }
493590 return self . run (
0 commit comments