ekazaev / route-composer

Protocol oriented, Cocoa UI abstractions based library that helps to handle view controllers composition, navigation and deep linking tasks in the iOS application. Can be used as the universal replacement for the Coordinator pattern.
MIT License
902 stars 64 forks source link

Crash in String(describing: dactory) call #102

Closed kadetlessy closed 1 year ago

kadetlessy commented 1 year ago

Hello Eugene!

We use RouterComposer in our app and encountered the following crash during navigation:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x6a80000000001e) in line # 55 String(describing: factory) of CompleteFactory implementation.

It happens from time and time and it's difficult to reproduce, but I can also see that this call logger?.log(.info("(String(describing: step)) hasn't found a corresponding view " in DefaultRouter precends that.

Will be happy to hear any leads on how to resolve it.

ekazaev commented 1 year ago

@kadetlessy Hi,

Thank you for the issue. TBH I use RouteComposer myself intensively and never saw anything like this. Do you have anything else to provide? Maybe it is being called not from main thread or something? Can you provide the entire stack trace? Also, does it happen in the production or in development build?

The crash itself if related to the memory access AFAIK. So it could be related to your own factory that CompleteFactory is wrapping.

kadetlessy commented 1 year ago

Hey @ekazaev,

This issue is definitely happening in the development build, I'm not sure about the production build though.

I have a full stack trace:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x350946ee0d9e)
    frame #0: 0x000000018005049c libobjc.A.dylib`objc_opt_respondsToSelector + 20
    frame #1: 0x000000018039e2d4 CoreFoundation`__CFCopyFormattingDescription + 612
    frame #2: 0x00000001803c8328 CoreFoundation`__CFStringAppendFormatCore + 10940
    frame #3: 0x00000001803d8404 CoreFoundation`CFStringAppendFormatAndArguments + 136
    frame #4: 0x00000001803c9f08 CoreFoundation`CFStringAppendFormat + 92
    frame #5: 0x000000018036a04c CoreFoundation`___CFXNotificationCenterCopyDebugInfo_block_invoke + 184
    frame #6: 0x000000018047501c CoreFoundation`_CFXNotificationRegistrarEnumerateObserverTable + 176
    frame #7: 0x0000000180474f40 CoreFoundation`_CFXNotificationRegistrarEnumerateObjectTable + 104
    frame #8: 0x0000000180474e94 CoreFoundation`_CFXNotificationRegistrarEnumerateNameTable + 168
    frame #9: 0x0000000180474d84 CoreFoundation`CFXNotificationRegistrarEnumerate + 56
    frame #10: 0x0000000180369f64 CoreFoundation`_CFXNotificationCenterCopyDebugInfo + 120
    frame #11: 0x0000000180b532e0 Foundation`-[NSNotificationCenter debugDescription] + 204
    frame #12: 0x0000000180980398 Foundation`merged protocol witness for Swift.CustomStringConvertible.description.getter : Swift.String in conformance __C.NSObject : Swift.CustomStringConvertible in Foundation + 28
    frame #13: 0x000000018bd53208 libswiftCore.dylib`Swift._debugPrint_unlocked<τ_0_0, τ_0_1 where τ_0_1: Swift.TextOutputStream>(τ_0_0, inout τ_0_1) -> () + 340
    frame #14: 0x000000018bddf66c libswiftCore.dylib`Swift._adHocPrint_unlocked<τ_0_0, τ_0_1 where τ_0_1: Swift.TextOutputStream>(_: τ_0_0, _: Swift.Mirror, _: inout τ_0_1, isDebugPrint: Swift.Bool) -> () + 380
    frame #15: 0x000000018bd53668 libswiftCore.dylib`Swift._debugPrint_unlocked<τ_0_0, τ_0_1 where τ_0_1: Swift.TextOutputStream>(τ_0_0, inout τ_0_1) -> () + 1460
    frame #16: 0x000000018bddf66c libswiftCore.dylib`Swift._adHocPrint_unlocked<τ_0_0, τ_0_1 where τ_0_1: Swift.TextOutputStream>(_: τ_0_0, _: Swift.Mirror, _: inout τ_0_1, isDebugPrint: Swift.Bool) -> () + 380
    frame #17: 0x000000018bd96f1c libswiftCore.dylib`Swift.String.init<τ_0_0>(describing: τ_0_0) -> Swift.String + 1736
  * frame #18: 0x000000010443fb4c BPRouting`CompleteFactory.description.getter(self=RouteComposer.CompleteFactory<SpainModule.BPTabBarControllerFactory> @ 0x000000016d3be1b0) at CompleteFactory.swift:55:9
    frame #19: 0x000000010443fc28 BPRouting`protocol witness for CustomStringConvertible.description.getter in conformance CompleteFactory<A> at <compiler-generated>:0
    frame #20: 0x000000018bd969a8 libswiftCore.dylib`Swift.String.init<τ_0_0>(describing: τ_0_0) -> Swift.String + 340
    frame #21: 0x000000010446ac94 BPRouting`AnyFactory<>.description.getter(self=RouteComposer.ContainerFactoryBox<RouteComposer.CompleteFactory<SpainModule.BPTabBarControllerFactory>> @ 0x000000016d3c1a20) at AnyFactoryBox.swift:53:9
    frame #22: 0x000000010446e158 BPRouting`protocol witness for CustomStringConvertible.description.getter in conformance ContainerFactoryBox<A> at <compiler-generated>:0
    frame #23: 0x000000018bd969a8 libswiftCore.dylib`Swift.String.init<τ_0_0>(describing: τ_0_0) -> Swift.String + 340
    frame #24: 0x00000001044604b4 BPRouting`DefaultRouter.FactoryDecorator.description.getter(self=RouteComposer.DefaultRouter.FactoryDecorator @ 0x000000016d3c23b0) at DefaultRouter+Extension.swift:261:13
    frame #25: 0x00000001044605d4 BPRouting`protocol witness for CustomStringConvertible.description.getter in conformance DefaultRouter.FactoryDecorator at <compiler-generated>:0
    frame #26: 0x000000018bd53208 libswiftCore.dylib`Swift._debugPrint_unlocked<τ_0_0, τ_0_1 where τ_0_1: Swift.TextOutputStream>(τ_0_0, inout τ_0_1) -> () + 340
    frame #27: 0x000000018bddf838 libswiftCore.dylib`Swift._adHocPrint_unlocked<τ_0_0, τ_0_1 where τ_0_1: Swift.TextOutputStream>(_: τ_0_0, _: Swift.Mirror, _: inout τ_0_1, isDebugPrint: Swift.Bool) -> () + 840
    frame #28: 0x000000018bd96f1c libswiftCore.dylib`Swift.String.init<τ_0_0>(describing: τ_0_0) -> Swift.String + 1736
    frame #29: 0x0000000104454c90 BPRouting`closure #1 in buildViewController #1 (result=success, self=RouteComposer.DefaultRouter @ 0x0000600002bcd600, previousViewController=0x0000000155853a00, completion=0x00000001044567e0 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.startNavigation(from: __C.UIViewController, building: Swift.Array<(factory: RouteComposer.AnyFactory, context: RouteComposer.AnyContext)>, performing: RouteComposer.DefaultRouter.GlobalTaskRunner, animated: Swift.Bool, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>, factories=0 values, postponedIntegrationHandler=0x0000600003f74f00, animated=true) in DefaultRouter.buildViewControllerStack(starting:using:animated:completion:) at DefaultRouter.swift:253:42
    frame #30: 0x0000000104458658 BPRouting`makeVisible #1 (viewController=0x0000000155853a00, completion=0x0000000104456984 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in buildViewController(from: __C.UIViewController) -> () at <compiler-generated>, self=RouteComposer.DefaultStackPresentationHandler @ 0x000060000345d7b0, parentViewControllers=0 values, animated=true, topParentViewController=nil) in DefaultStackPresentationHandler.makeVisibleInParentContainers(_:animated:completion:) at DefaultStackPresentationHandler.swift:68:17
    frame #31: 0x0000000104457ce4 BPRouting`DefaultStackPresentationHandler.makeVisibleInParentContainers(viewController=0x0000000155853a00, animated=true, completion=0x0000000104456984 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in buildViewController(from: __C.UIViewController) -> () at <compiler-generated>, self=RouteComposer.DefaultStackPresentationHandler @ 0x000060000345d7b0) at DefaultStackPresentationHandler.swift:95:9
    frame #32: 0x0000000104458ad0 BPRouting`protocol witness for StackPresentationHandler.makeVisibleInParentContainers(_:animated:completion:) in conformance DefaultStackPresentationHandler at <compiler-generated>:0
    frame #33: 0x0000000104454928 BPRouting`buildViewController #1 (previousViewController=0x0000000155853a00, self=RouteComposer.DefaultRouter @ 0x0000600002bb2e70, animated=true, completion=0x00000001044567e0 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.startNavigation(from: __C.UIViewController, building: Swift.Array<(factory: RouteComposer.AnyFactory, context: RouteComposer.AnyContext)>, performing: RouteComposer.DefaultRouter.GlobalTaskRunner, animated: Swift.Bool, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>, factories=0 values, postponedIntegrationHandler=0x0000600003f74f00) in DefaultRouter.buildViewControllerStack(starting:using:animated:completion:) at DefaultRouter.swift:239:38
    frame #34: 0x0000000104454784 BPRouting`DefaultRouter.buildViewControllerStack(rootViewController=0x0000000155853a00, factories=1 value, animated=true, completion=0x00000001044567e0 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.startNavigation(from: __C.UIViewController, building: Swift.Array<(factory: RouteComposer.AnyFactory, context: RouteComposer.AnyContext)>, performing: RouteComposer.DefaultRouter.GlobalTaskRunner, animated: Swift.Bool, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>, self=RouteComposer.DefaultRouter @ 0x0000600002bb2e70) at DefaultRouter.swift:280:9
    frame #35: 0x0000000104454304 BPRouting`closure #1 in closure #1 in DefaultRouter.startNavigation(result=success, completion=0x0000000104452950 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.navigate<A, B where B: __C.UIViewController>(to: RouteComposer.DestinationStep<B, A>, with: A, animated: Swift.Bool, completion: Swift.Optional<(RouteComposer.RoutingResult) -> ()>) throws -> () at <compiler-generated>, self=RouteComposer.DefaultRouter @ 0x0000600002bb2e70, viewController=0x0000000155853a00, buildingInputStack=1 value, animated=true, taskStack=0x0000600001d7b9c0) at DefaultRouter.swift:210:17
    frame #36: 0x0000000104457860 BPRouting`DefaultStackPresentationHandler.dismissPresented(viewController=0x0000000155853a00, animated=true, completion=0x0000000104456778 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.startNavigation(from: __C.UIViewController, building: Swift.Array<(factory: RouteComposer.AnyFactory, context: RouteComposer.AnyContext)>, performing: RouteComposer.DefaultRouter.GlobalTaskRunner, animated: Swift.Bool, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>, self=RouteComposer.DefaultStackPresentationHandler @ 0x000060000345d7b0) at DefaultStackPresentationHandler.swift:51:13
    frame #37: 0x0000000104458ab8 BPRouting`protocol witness for StackPresentationHandler.dismissPresented(from:animated:completion:) in conformance DefaultStackPresentationHandler at <compiler-generated>:0
    frame #38: 0x00000001044541c8 BPRouting`closure #1 in DefaultRouter.startNavigation(result=success, self=RouteComposer.DefaultRouter @ 0x000060000290c8d0, completion=0x0000000104452950 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.navigate<A, B where B: __C.UIViewController>(to: RouteComposer.DestinationStep<B, A>, with: A, animated: Swift.Bool, completion: Swift.Optional<(RouteComposer.RoutingResult) -> ()>) throws -> () at <compiler-generated>, viewController=0x0000000155853a00, initialControllerDescription="<BPmeCore.RootNavigationController: 0x155853a00>", animated=true, buildingInputStack=1 value, taskStack=0x0000600001d7b9c0) at DefaultRouter.swift:202:38
    frame #39: 0x00000001044566ac BPRouting`partial apply for closure #1 in DefaultRouter.startNavigation(from:building:performing:animated:completion:) at <compiler-generated>:0
    frame #40: 0x000000010445d798 BPRouting`closure #1 in runInterceptor #1 (result=success, completion=0x0000000104456668 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.DefaultRouter.startNavigation(from: __C.UIViewController, building: Swift.Array<(factory: RouteComposer.AnyFactory, context: RouteComposer.AnyContext)>, performing: RouteComposer.DefaultRouter.GlobalTaskRunner, animated: Swift.Bool, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>, interceptors=0 values) in DefaultRouter.InterceptorRunner.perform(completion:) at DefaultRouter+Extension.swift:49:25
    frame #41: 0x0000000104473948 BPRouting`closure #1 in RoutingInterceptorBox.perform(result=success, self=RouteComposer.RoutingInterceptorBox<RouteComposer.NavigationDelayingInterceptor<Swift.Optional<Any>>> @ 0x00006000022164b0, completion=0x0000000104463468 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in runInterceptor(interceptor: (interceptor: RouteComposer.AnyRoutingInterceptor, context: RouteComposer.AnyContext)) -> () at <compiler-generated>) at RoutingInterceptorBox.swift:38:17
    frame #42: 0x0000000104439da8 BPRouting`NavigationDelayingInterceptor.perform(context=some, completion=0x0000000104473a74 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.RoutingInterceptorBox.perform(with: RouteComposer.AnyContext, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>, self=RouteComposer.NavigationDelayingInterceptor<Swift.Optional<Any>> @ 0x0000600002159418) at NavigationDelayInterceptor.swift:73:13
    frame #43: 0x000000010443a07c BPRouting`closure #1 in NavigationDelayingInterceptor.perform(self=RouteComposer.NavigationDelayingInterceptor<Swift.Optional<Any>> @ 0x0000600002159418, context=some, completion=0x0000000104473a74 BPRouting`partial apply forwarder for closure #1 (RouteComposer.RoutingResult) -> () in RouteComposer.RoutingInterceptorBox.perform(with: RouteComposer.AnyContext, completion: (RouteComposer.RoutingResult) -> ()) -> () at <compiler-generated>) at NavigationDelayInterceptor.swift:84:13
    frame #44: 0x000000010440dac8 BPRouting`thunk for @escaping @callee_guaranteed () -> () at <compiler-generated>:0
    frame #45: 0x000000010344dd50 libdispatch.dylib`_dispatch_client_callout + 16
    frame #46: 0x0000000103451208 libdispatch.dylib`_dispatch_continuation_pop + 756
    frame #47: 0x00000001034688d4 libdispatch.dylib`_dispatch_source_invoke + 1676
    frame #48: 0x000000010345e634 libdispatch.dylib`_dispatch_main_queue_drain + 848
    frame #49: 0x000000010345e2d4 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 40
    frame #50: 0x000000018039a784 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    frame #51: 0x0000000180394de4 CoreFoundation`__CFRunLoopRun + 1912
    frame #52: 0x0000000180394254 CoreFoundation`CFRunLoopRunSpecific + 584
    frame #53: 0x0000000188eb7c9c GraphicsServices`GSEventRunModal + 160
    frame #54: 0x000000010b252ff0 UIKitCore`-[UIApplication _run] + 868
    frame #55: 0x000000010b256f3c UIKitCore`UIApplicationMain + 124
    frame #56: 0x000000010392c454 libswiftUIKit.dylib`UIKit.UIApplicationMain(Swift.Int32, Swift.Optional<Swift.UnsafeMutablePointer<Swift.UnsafeMutablePointer<Swift.Int8>>>, Swift.Optional<Swift.String>, Swift.Optional<Swift.String>) -> Swift.Int32 + 100
    frame #57: 0x0000000102a90760 bpme`static UIApplicationDelegate.main() at <compiler-generated>:0
    frame #58: 0x0000000102a9068c bpme`static MainEntryPoint.main(self=bpme.MainEntryPoint) at MainEntryPoint.swift:15:25
    frame #59: 0x0000000102a9078c bpme`static MainEntryPoint.$main(self=bpme.MainEntryPoint) at MainEntryPoint.swift:11:1
    frame #60: 0x0000000102a91520 bpme`main at MainEntryPoint.swift:0
    frame #61: 0x0000000102ffd514 dyld_sim`start_sim + 20
    frame #62: 0x0000000102dd1f28 dyld`start + 2236

Please let me know if I can do anything else. It's happening after switching several times between a set of controllers with and without tab bar, but I can't say identify the exact steps to reproduce.

ekazaev commented 1 year ago

@kadetlessy Hi,

Thank you for the information provided. Originally i thought that your problem is just that you need to clean the DeriveData folder 😀

But now with the details I have a question. So it is definitely happening when the Router tries to get a description of your own BPTabBarControllerFactory. but inside of this class the method that generates the entitys debugDescription starts to generate it and includes the description of the NSNotifocationCenter and crashes there.

Can you have a look why is that happening? Did you override it? Is NSNotifocationCenter exposed there somehow? Without seeing your code I don't understand how the NSNotifocationCenter even gets there.

Another thing I noticed. I see you are using NavigationDelayingInterceptor. I assume you are not using the .wait strategy there. Just to doublecheck.

ekazaev commented 1 year ago

@kadetlessy Hi,

Any updates on this issue?

ekazaev commented 1 year ago

@kadetlessy Please feel free to reopen the issue if you have something else to add. Best of luck.