0

I'm seeing an unexplained crash on my iOS app built with SwiftUI. It only affects some users, and I can't manage to reproduce locally.

Here is the stack trace:

Fatal Exception: NSInvalidArgumentException

<_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS_19SidebarStyleContext_: 0x110859800>
is pushing the same view controller instance(<_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS_14NoStyleContext_: 0x11088a400>)
more than once which is not supported and is most likely an error in the application : `com.myapp`


Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x1893a186c __exceptionPreprocess
1  libobjc.A.dylib                0x19e3bcc50 objc_exception_throw
2  UIKitCore                      0x18b575514 -[UINavigationController pushViewController:transition:forceImmediate:]
3  UIKitCore                      0x18b5751f4 -[UINavigationController pushViewController:animated:]
4  UIKitCore                      0x18b6047c8 __45-[UISplitViewControllerPanelImpl showColumn:]_block_invoke
5  UIKitCore                      0x18b57eda8 -[UINavigationController _executeSplitViewControllerActions:]
6  UIKitCore                      0x18b6045bc -[UISplitViewControllerPanelImpl showColumn:]
7  UIKitCore                      0x18b5e4c54 -[UISplitViewController showColumn:]
8  SwiftUI                        0x1903784f4 closure #1 in closure #1 in NavigationBridge_PhoneTV.push(_:onto:animated:)
9  SwiftUI                        0x19042728c thunk for @escaping @callee_guaranteed () -> ()
10 UIKitCore                      0x18c23f544 -[_UIAfterCACommitBlock run]
11 UIKitCore                      0x18bd6700c _runAfterCACommitDeferredBlocks
12 UIKitCore                      0x18bd559a0 _cleanUpAfterCAFlushAndRunDeferredBlocks
13 UIKitCore                      0x18bd89bb4 _afterCACommitHandler
14 CoreFoundation                 0x18931c358 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
15 CoreFoundation                 0x1893165c4 __CFRunLoopDoObservers
16 CoreFoundation                 0x189316b74 __CFRunLoopRun
17 CoreFoundation                 0x18931621c CFRunLoopRunSpecific
18 GraphicsServices               0x1a0ee2784 GSEventRunModal
19 UIKitCore                      0x18bd56ee8 -[UIApplication _run]
20 UIKitCore                      0x18bd5c75c UIApplicationMain
21 MYAPP                          0x100dbecc0 main + 7 (PushupsMode.swift:7)
22 libdyld.dylib                  0x188fd66b0 start

Looking at PushupsMode.swift:7 it seems completely unrelated:

import Foundation

extension WorkoutModel {
    mutating func startPushups() {
        var pushupsCount = 10 + p.intensityOptionPicked * 10
        
        if(round > 6 || round < 3) { // <<--- this is the line crashing
            pushupsCount = Int(pushupsCount / 2)
        }

        // More code after that point
    }
}

The round variable is defined in another file, but there's nothing really significant around it:

import Foundation
import SwiftUI

struct WorkoutModel: Identifiable {
    // bunch of stuff before
    var round: Int = -1
    // bunch of stuff after
} 

Obviously looking at the error message, it seems like something is getting pushed twice... however since I'm using SwiftUI I'm not entirely sure how I could have even done that.

Any pointers would be appreciated!

marcgg
  • 65,020
  • 52
  • 178
  • 231
  • I'd be curious about where `round` is declared. Since It seems to be crashing on an innocuous-looking line, I'd investigate why that line in particular is a problem. Maybe there are threading issues with the multiple controllers? Though I don't know why there would be multiple pushes. – user212514 Mar 08 '21 at 06:54
  • 1
    Is there a business logic that you subscribed to (waiting) something, then based on that you are navigating.. So this code block may be notified more than needed ? – Enes Karaosman Mar 08 '21 at 08:42
  • @user212514 I've updated the question, but the whole file is not related to pushing views – marcgg Mar 08 '21 at 19:53
  • @EnesKaraosman The `if(round > 6 || round < 3) ` is actually not even supposed to be called at that point if I'm following what's in crashlytics. It's a "mode" that is not used for the situation that caused the crash. – marcgg Mar 08 '21 at 19:54
  • Can you see in your crashlogs if it is related to a specific iOS version? – de. Mar 08 '21 at 21:27
  • Also, did you try debugging it by triggering multiple segues in quick succession (e.g. double-tap on cell)? – de. Mar 08 '21 at 21:28
  • @de.I tried tapping quickly both in the simulator & on device. I don't see anything specific to an iOS version (happens on 13 & 14) – marcgg Mar 10 '21 at 20:01
  • I think the sidebar was pushed twice to the stack. Not that the WorkoutModel is the real thing that threw the issue. I did find [this](https://stackoverflow.com/questions/27993344/nsinvalidargumentexception-pushing-the-same-view-controller-instance-more-than) and [pushing same view twice](https://stackoverflow.com/questions/7083124/pushing-the-same-view-controller-instance-more-than-once-is-not-supported-exce/10584277) which might give some ideas on how to correct – hppycoder Mar 12 '21 at 22:19

3 Answers3

0

Your problem may be that you are defining pushupsCount as an Int( on PushupsMode.swift:8 which is causing the exception on :7 from :8 failing pre-execution. Try defining it as pushupsCount = Int pushupsCount / 2 .

9pfs
  • 560
  • 5
  • 17
0

Using pushViewController:transition:forceImmediate is not a good idea because pushViewController:animated will be calling on this undocumented method. Rather than changing transition this way you can use other documented methods for changing animation. This thread might be helpful for you. You will also need to add guard in pushViewController:animated and will also need to set transition.duration. Calling pushViewController again and again is perhaps causing crash of app.

0

This problem is caused when you place your navigationLink inside of a List with observed data.

How to fix :

Remove NavigationLink from inside of the list and place it outside.