pointfreeco / swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
https://www.pointfree.co/collections/composable-architecture
MIT License
12.22k stars 1.42k forks source link

partial apply for closure #2 in _DependencyKeyWritingReducer.reduce(into:action:) #3226

Closed HyungGilHam closed 2 months ago

HyungGilHam commented 2 months ago

Description

We have integrated Firebase Crashlytics to capture the crash details. Below is the detailed crash report from Firebase Crashlytics:

          Crashed: com.apple.main-thread
0  LiivonMINI-iOS                 0x10cd31c closure #1 in KBMapRightToolBarReducer.body.getter + 4360442652 (<compiler-generated>:4360442652)
1  LiivonMINI-iOS                 0xb6941c specialized Scope.reduce(into:action:) + 4354790428 (<compiler-generated>:4354790428)
2  LiivonMINI-iOS                 0xb64bec specialized ReducerBuilder._Sequence.reduce(into:action:) + 4354771948 (<compiler-generated>:4354771948)
3  LiivonMINI-iOS                 0xb64910 specialized ReducerBuilder._Sequence.reduce(into:action:) + 4354771216 (<compiler-generated>:4354771216)
4  LiivonMINI-iOS                 0xb63d94 protocol witness for Reducer.reduce(into:action:) in conformance MapReducer + 4354768276 (<compiler-generated>:4354768276)
5  LiivonMINI-iOS                 0x14e327c partial apply for closure #2 in _DependencyKeyWritingReducer.reduce(into:action:) + 171 (DependencyKeyWritingReducer.swift:171)
6  LiivonMINI-iOS                 0x15e0738 closure #1 in closure #1 in closure #1 in withDependencies<A>(_:operation:) + 4365764408
7  LiivonMINI-iOS                 0x15e42e4 partial apply for closure #1 in closure #1 in withDependencies<A>(_:operation:) + 31 (WithDependencies.swift:31)
8  libswift_Concurrency.dylib     0x21204 TaskLocal.withValue<A>(_:operation:file:line:) + 304
9  LiivonMINI-iOS                 0x15e06a4 closure #1 in withDependencies<A>(_:operation:) + 4365764260
10 LiivonMINI-iOS                 0x15e04cc withDependencies<A>(_:operation:) + 27 (WithDependencies.swift:27)
11 LiivonMINI-iOS                 0x14e31f0 _DependencyKeyWritingReducer.reduce(into:action:) + 173 (DependencyKeyWritingReducer.swift:173)
12 LiivonMINI-iOS                 0x150ae24 open #1 <A, B, C>(reducer:) in RootStore.send(_:originatingFrom:) + 56 (RootStore.swift:56)
13 LiivonMINI-iOS                 0x150cedc closure #1 in closure #3 in closure #1 in open #1 <A, B, C>(reducer:) in RootStore.send(_:originatingFrom:) + 4364898012
14 LiivonMINI-iOS                 0x150e2b4 partial apply for closure #1 in closure #3 in closure #1 in open #1 <A, B, C>(reducer:) in RootStore.send(_:originatingFrom:) + 4364903092
15 LiivonMINI-iOS                 0x150e290 partial apply for closure #1 in closure #1 in closure #1 in closure #3 in open #1 <A, B, C>(reducer:) in RootStore.send(_:originatingFrom:) + 4364903056
16 LiivonMINI-iOS                 0x15e2e78 partial apply for closure #2 in DependencyValues.Continuation.yield<A>(_:) + 303 (WithDependencies.swift:303)
17 LiivonMINI-iOS                 0x15e0738 closure #1 in closure #1 in closure #1 in withDependencies<A>(_:operation:) + 4365764408
18 LiivonMINI-iOS                 0x15e42e4 partial apply for closure #1 in closure #1 in withDependencies<A>(_:operation:) + 31 (WithDependencies.swift:31)
19 libswift_Concurrency.dylib     0x21204 TaskLocal.withValue<A>(_:operation:file:line:) + 304
20 LiivonMINI-iOS                 0x15e06a4 closure #1 in withDependencies<A>(_:operation:) + 4365764260
21 LiivonMINI-iOS                 0x15e1da4 DependencyValues.Continuation.yield<A>(_:) + 27 (WithDependencies.swift:27)
22 LiivonMINI-iOS                 0x150cd40 closure #1 in closure #1 in closure #3 in open #1 <A, B, C>(reducer:) in RootStore.send(_:originatingFrom:) + 4364897600
23 LiivonMINI-iOS                 0x150e278 partial apply for closure #1 in closure #1 in closure #3 in open #1 <A, B, C>(reducer:) in RootStore.send(_:originatingFrom:) + 4364903032 (<compiler-generated>:4364903032)
24 LiivonMINI-iOS                 0xb6c014 specialized closure #1 in closure #1 in closure #1 in closure #2 in Effect.map<A>(_:) + 4354801684 (<compiler-generated>:4354801684)
25 LiivonMINI-iOS                 0x10cee70 (8) suspend resume partial function for closure #8 in closure #1 in KBMapRightToolBarReducer.body.getter + 110 (MapRightToolBarReducer.swift:110)
26 libswift_Concurrency.dylib     0x4d764 swift::runJobInEstablishedExecutorContext(swift::Job*) + 436
27 libswift_Concurrency.dylib     0x4e9c8 swift_job_runImpl(swift::Job*, swift::ExecutorRef) + 72
28 libdispatch.dylib              0x124b4 _dispatch_main_queue_drain + 748
29 libdispatch.dylib              0x121b8 _dispatch_main_queue_callback_4CF + 44
30 CoreFoundation                 0x56710 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
31 CoreFoundation                 0x53914 __CFRunLoopRun + 1996
32 CoreFoundation                 0x52cd8 CFRunLoopRunSpecific + 608
33 GraphicsServices               0x11a8 GSEventRunModal + 164
34 UIKitCore                      0x40a90c -[UIApplication _run] + 888
35 UIKitCore                      0x4be9d0 UIApplicationMain + 340
36 LiivonMINI-iOS                 0xebfd0c main + 34 (AppDelegate.swift:34)
37 ???                            0x1ac4dde4c (누락)

Checklist

Expected behavior

The crash appears to be related to the use of concurrency and dependency injection within the reducer.

Actual behavior

Relevant Code

case .drawToolbar(let model, let list):
    return .run { send in
        await send(.saveState)
        await send(.checkLegend)
        await send(.bottomSalesCountHiddden)
        if let changed = list.filter({$0.type == model?.type}).first {
            await send(.loadMarker(changed)) 
            await send(.loadMapArea(changed))
        } else {
            await send(.loadMarker(nil)) <<<<------ here
        }
    }
}

Crash Location: await send(.loadMarker(nil)) Conditions: This action is called multiple times.

Steps to reproduce

Since it came out as a crash report, it is difficult to reproduce. Are there any expected problems?

The Composable Architecture version information

1.11.2

Destination operating system

iPadOS 17.4.1, iPadOS 17.5.1, iOS 18.0

Xcode version information

Version 15.3

Swift Compiler version information

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0
HyungGilHam commented 2 months ago

Currently testing with debounce.

case .drawToolbar(let model, let list):
    return .run { send in
        await send(.saveState)
        await send(.checkLegend)
        await send(.bottomSalesCountHiddden)
        if let changed = list.filter({$0.type == model?.type}).first {
            await send(.loadMarker(changed)) 
            await send(.loadMapArea(changed))
        } else {
            await send(.loadMarker(nil))
        }
    }.debounce(id: DebounceId(), for: 0.3, scheduler: mainQueue)

But ultimately, I think we have to find the problem.

stephencelis commented 2 months ago

@HyungGilHam I think we need more information before we can consider this a library bug. If you can share a repro that definitely shows a problem in our library, we'd be happy to track it here, but for now I think we should convert this to a discussion till you've gathered more information.