Skip to content

Commit 7935583

Browse files
stephencelismluisbrown
authored andcommitted
Only warn for unused binding actions sent from view stores (#1163)
* Only warn for unused binding actions sent from view stores * Apply suggestions from code review * wip * wip
1 parent 27691a7 commit 7935583

File tree

2 files changed

+66
-66
lines changed

2 files changed

+66
-66
lines changed

Sources/ComposableArchitecture/SwiftUI/Binding.swift

Lines changed: 66 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,19 @@ import SwiftUI
288288
) -> Binding<Value> {
289289
self.binding(
290290
get: { $0[keyPath: keyPath].wrappedValue },
291-
send: {
292-
.binding(.set(keyPath, $0, bindableActionType: Action.self, file: file, line: line))
291+
send: { value in
292+
#if DEBUG
293+
let debugger = BindableActionViewStoreDebugger(
294+
value: value, bindableActionType: Action.self, file: file, line: line
295+
)
296+
let set: (inout State) -> Void = {
297+
$0[keyPath: keyPath].wrappedValue = value
298+
debugger.wasCalled = true
299+
}
300+
#else
301+
let set: (inout State) -> Void = { $0[keyPath: keyPath].wrappedValue = value }
302+
#endif
303+
return .binding(.init(keyPath: keyPath, set: set, value: value))
293304
}
294305
)
295306
}
@@ -329,27 +340,12 @@ public struct BindingAction<Root>: Equatable {
329340
/// path.
330341
public static func set<Value: Equatable>(
331342
_ keyPath: WritableKeyPath<Root, BindableState<Value>>,
332-
_ value: Value,
333-
bindableActionType: Any.Type? = nil,
334-
file: StaticString = #fileID,
335-
line: UInt = #line
343+
_ value: Value
336344
) -> Self {
337-
#if DEBUG
338-
let debugger = Debugger(
339-
value: value, bindableActionType: bindableActionType, file: file, line: line
340-
)
341-
let set: (inout Root) -> Void = {
342-
$0[keyPath: keyPath].wrappedValue = value
343-
debugger.wasCalled = true
344-
}
345-
#else
346-
let set: (inout Root) -> Void = { $0[keyPath: keyPath].wrappedValue = value }
347-
#endif
348345
return .init(
349346
keyPath: keyPath,
350-
set: set,
351-
value: value,
352-
valueIsEqualTo: { $0 as? Value == value }
347+
set: { $0[keyPath: keyPath].wrappedValue = value },
348+
value: value
353349
)
354350
}
355351

@@ -372,48 +368,18 @@ public struct BindingAction<Root>: Equatable {
372368
keyPath == bindingAction.keyPath
373369
}
374370

375-
#if DEBUG
376-
private class Debugger<Value> {
377-
let value: Value
378-
let bindableActionType: Any.Type?
379-
let file: StaticString
380-
let line: UInt
381-
var wasCalled = false
382-
383-
init(value: Value, bindableActionType: Any.Type?, file: StaticString, line: UInt) {
384-
self.value = value
385-
self.bindableActionType = bindableActionType
386-
self.file = file
387-
self.line = line
388-
}
389-
390-
deinit {
391-
guard self.wasCalled else {
392-
let action = """
393-
\(bindableActionType.map { "\($0).binding(" } ?? "\(BindingAction.self)")\
394-
.set(_, \(self.value))\
395-
\(bindableActionType != nil ? ")" : "")
396-
"""
397-
runtimeWarning(
398-
"""
399-
A binding action created at "%@:%d" was not handled:
400-
401-
Action:
402-
%@
403-
404-
To fix this, invoke the "binding()" method on your feature's reducer.
405-
""",
406-
[
407-
"\(self.file)",
408-
self.line,
409-
action,
410-
]
411-
)
412-
return
413-
}
414-
}
415-
}
416-
#endif
371+
init<Value: Equatable>(
372+
keyPath: WritableKeyPath<Root, BindableState<Value>>,
373+
set: @escaping (inout Root) -> Void,
374+
value: Value
375+
) {
376+
self.init(
377+
keyPath: keyPath,
378+
set: set,
379+
value: value,
380+
valueIsEqualTo: { $0 as? Value == value }
381+
)
382+
}
417383
}
418384
#endif
419385

@@ -600,3 +566,41 @@ extension BindingAction: CustomDumpReflectable {
600566
}
601567
}
602568
#endif
569+
570+
#if DEBUG
571+
private final class BindableActionViewStoreDebugger<Value> {
572+
let value: Value
573+
let bindableActionType: Any.Type
574+
let file: StaticString
575+
let line: UInt
576+
var wasCalled = false
577+
578+
init(value: Value, bindableActionType: Any.Type, file: StaticString, line: UInt) {
579+
self.value = value
580+
self.bindableActionType = bindableActionType
581+
self.file = file
582+
self.line = line
583+
}
584+
585+
deinit {
586+
guard self.wasCalled else {
587+
runtimeWarning(
588+
"""
589+
A binding action sent from a view store at "%@:%d" was not handled:
590+
591+
Action:
592+
%@
593+
594+
To fix this, invoke the "binding()" method on your feature's reducer.
595+
""",
596+
[
597+
"\(self.file)",
598+
self.line,
599+
"\(self.bindableActionType).binding(.set(_, \(self.value)))",
600+
]
601+
)
602+
return
603+
}
604+
}
605+
}
606+
#endif

Tests/ComposableArchitectureTests/DebugTests.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,10 +201,6 @@ final class DebugTests: XCTestCase {
201201
)
202202
"""#
203203
)
204-
205-
// NB: Call setter to avoid runtime warning
206-
var state = State()
207-
action.set(&state)
208204
}
209205
#endif
210206
}

0 commit comments

Comments
 (0)