Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in installMaskingView #348

Open
amaurydavid opened this issue Sep 25, 2019 · 15 comments
Open

Crash in installMaskingView #348

amaurydavid opened this issue Sep 25, 2019 · 15 comments

Comments

@amaurydavid
Copy link

amaurydavid commented Sep 25, 2019

Hello :)

I've posted almost 1 year ago in #253 an issue where my app crashed due to autolayout issue.
At the time i've updated SwiftMessage to 6.0.2 and the crash is still there, but slightly differs from the old one.
With SwiftMessage 4.1.4:

Fatal Exception: NSInternalInconsistencyException
Impossible to set up layout with view hierarchy unprepared for constraint.
0  CoreFoundation                 0x1835a2d8c __exceptionPreprocess
1  libobjc.A.dylib                0x18275c5ec objc_exception_throw
2  CoreFoundation                 0x1835a2bf8 +[NSException raise:format:]
3  Foundation                     0x183f92fa0 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
4  UIKit                          0x18dcd1f78 __120-[UIView(UIConstraintBasedLayout) _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:]_block_invoke_2
5  UIKit                          0x18d1c29ec -[UIView(UIConstraintBasedLayout) _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:]
6  UIKit                          0x18d1c2804 -[UIView(UIConstraintBasedLayout) _tryToAddConstraintWithoutUpdatingConstraintsArray:roundingAdjustment:mutuallyExclusiveConstraints:]
7  UIKit                          0x18d4b1254 __50-[UIView(UIConstraintBasedLayout) addConstraints:]_block_invoke
8  Foundation                     0x183ef1500 -[NSISEngine withBehaviors:performModifications:]
9  UIKit                          0x18d2670cc -[UIView(UIConstraintBasedLayout) addConstraints:]
10 SwiftMessages                  0x104e08dac specialized installMaskingView #1 (containerView:) in Presenter.install() (Presenter.swift:344)
11 SwiftMessages                  0x104e065d0 Presenter.install() (Presenter.swift)
12 SwiftMessages                  0x104e097e4 specialized Presenter.show(completion:) (Presenter.swift:116)
13 SwiftMessages                  0x104e0c3b8 closure #1 in SwiftMessages.dequeueNext() (SwiftMessages.swift:539)
14 SwiftMessages                  0x104e19088 _T0Ieg_IeyB_TR (TopBottomAnimation.swift)
15 libdispatch.dylib              0x182e94aa0 _dispatch_call_block_and_release
16 libdispatch.dylib              0x182e94a60 _dispatch_client_callout
17 libdispatch.dylib              0x182ea165c _dispatch_main_queue_callback_4CF$VARIANT$mp
18 CoreFoundation                 0x18354b070 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
19 CoreFoundation                 0x183548bc8 __CFRunLoopRun
20 CoreFoundation                 0x183468da8 CFRunLoopRunSpecific
21 GraphicsServices               0x18544e020 GSEventRunModal
22 UIKit                          0x18d488758 UIApplicationMain
23 MyApp                          0x1026ff028 main (AppDelegate.swift:28)
24 libdyld.dylib                  0x182ef9fc0 start

With SwiftMessage 6.0.2:


Fatal Exception: NSGenericExceptionUnable to activate constraint with anchors <NSLayoutYAxisAnchor:0x282e77d00 "SwiftMessages.MaskingView:0x108b19e20.bottom"> and <NSLayoutYAxisAnchor:0x282e71e80 "UITabBar:0x108a04ee0.top"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal. Raw Text
--
0 | CoreFoundation | __exceptionPreprocess
1 | libobjc.A.dylib | objc_exception_throw
2 | CoreFoundation | -[NSCache init]
3 | Foundation | -[NSLayoutConstraint _setActive:mutuallyExclusiveConstraints:]
4 | SwiftMessages | <compiler-generated> line 0installMaskingView #1 (containerView:) in Presenter.install()
5 | SwiftMessages | Presenter.swift line 401Presenter.install() + 401
6 | SwiftMessages | <compiler-generated> line 0Presenter.show(completion:)
7 | SwiftMessages | SwiftMessages.swift line 547closure #1 in SwiftMessages.dequeueNext() + 547
8 | SwiftMessages | <compiler-generated> line 0thunk for @escaping @callee_guaranteed () -> ()
9 | libdispatch.dylib | _dispatch_call_block_and_release
10 | libdispatch.dylib | _dispatch_client_callout
11 | libdispatch.dylib | _dispatch_main_queue_callback_4CF$VARIANT$mp
12 | CoreFoundation | __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
13 | CoreFoundation | __CFRunLoopRun
14 | CoreFoundation | CFRunLoopRunSpecific
15 | GraphicsServices | GSEventRunModal
16 | UIKitCore | UIApplicationMain
17 | MyApp | AppDelegate.swift line 28main + 28
18 | libdyld.dylib | start

Here is an example of the way I show a message:

let view = MessageView.viewFromNib(layout: .messageView)
    let buttonTapHandler: ((UIButton ) -> Void)? = { _ in
      SwiftMessages.hideAll()
    }
    let buttonImage = Asset.Common.erroriconsubtlecustom.image
    view.configureContent(title: title, body: body, iconImage: nil, iconText: nil, buttonImage: buttonImage, buttonTitle: nil, buttonTapHandler: buttonTapHandler)
    view.backgroundColor = ColorName.weather.color
    view.titleLabel?.textColor = .white
    view.bodyLabel?.textColor = .white
    view.button?.tintColor = .white
    view.titleLabel?.font = FontFamily.SanFranciscoText.heavy.font(size: 12)
    view.bodyLabel?.numberOfLines = 3
    view.bodyLabel?.font = FontFamily.SanFranciscoText.regular.font(size: 13)
    view.tapHandler = tapHandler

    var config = SwiftMessages.defaultConfig
    config.presentationStyle = .bottom
    config.duration = .forever
    config.interactiveHide = true

    SwiftMessages.show(config: config, view: view)

Messages that seems to crash are presented in theviewDidAppear of a UITabBarViewController subclass, with a UINavigationController as parent of the message

Updating to SwiftMessage 7.0.1 isn't an option for now as it requires Xcode 11 which I don't plan to use really soon (bugs, project compatibility, etc.).

@wtmoose
Copy link
Member

wtmoose commented Sep 25, 2019

Any reason why you don’t go with 7.0.0?

@amaurydavid
Copy link
Author

Nah, I've seen that 7.0.1 needed Xcode 11 and I supposed it was also the case for the 7.0.0. I'll make the update if possible.

@MaoDaAmargura
Copy link

MaoDaAmargura commented Oct 16, 2019

I have a similar issue in 7.0.0.

0  CoreFoundation                 0x1aa285c30 __exceptionPreprocess
1  libobjc.A.dylib                0x1a9fa00c8 objc_exception_throw
2  Foundation                     0x1aa55eb8c -[NSLayoutConstraint isActive]
3  MyApp                          0x105841d2c installMaskingView #1 (containerView:) in Presenter.install() (<compiler-generated>)
4  MyApp                          0x1058414e0 Presenter.install() + 412 (Presenter.swift:412)
5  MyApp                          0x10583f298 Presenter.show(completion:) (<compiler-generated>)
6  MyApp                          0x105848a58 closure #1 in SwiftMessages.dequeueNext() + 552 (SwiftMessages.swift:552)
7  MyApp                          0x104ce8554 thunk for @escaping @callee_guaranteed () -> () (<compiler-generated>)
8  libdispatch.dylib              0x1a9f2bbb0 _dispatch_call_block_and_release
9  libdispatch.dylib              0x1a9f2d00c _dispatch_client_callout
10 libdispatch.dylib              0x1a9f38cd8 _dispatch_main_queue_callback_4CF
11 CoreFoundation                 0x1aa200e20 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
12 CoreFoundation                 0x1aa1fbb7c __CFRunLoopRun
13 CoreFoundation                 0x1aa1fb098 CFRunLoopRunSpecific
14 GraphicsServices               0x1b4365534 GSEventRunModal
15 UIKitCore                      0x1ae31b7ac UIApplicationMain
16 MyApp                          0x104cb4c90 main + 15 (main.m:15)
17 libdyld.dylib                  0x1aa07af30 (Missing)

It crashes with the exception:

Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x281594b80 "SwiftMessages.MaskingView:0x1564e2a60.bottom"> and <NSLayoutYAxisAnchor:0x281594d80 "UITabBar:0x151d09c30.top"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.

My SwiftMessages are displayed using the block creation pattern SwiftMessages.show(config, {}), inside UIViewController subclasses that are the root view controller of a UINavigationController that is in the viewControllers of a UITabBarController.

This happens to approximately 0.18% of users in production. I've not yet been able to reproduce it myself.

I'm upgrading to 7.0.1 this release and will keep thread apprised.

@wtmoose
Copy link
Member

wtmoose commented Oct 16, 2019

Ugh...18% of users is the worst kind of crash since my chance of reproducing it is very slim :(

Any chance that they're jailbroken? Or any other commonalities? I've had crashes with jailbroken users in the past.

@amaurydavid
Copy link
Author

Here are some additional infos from Crashlytics for this crash:
100% of crashes are on iPhone
68% on iOS 13, 29% on iOS 12.
0% in background
0% jailbroken

While the audience of the app is:
80% on iPhone, 20% on iPad
57% on iOS 13, 34% on iOS 12

It looks it only crashes on iPhone, and has a bit more probability to happen using iOS 13.

@wtmoose
Copy link
Member

wtmoose commented Oct 17, 2019

My best guess is UITabBar does some weird internal stuff that leads to this. Do you need to install the message into the tab bar? The only reason I know if is if you’re trying to slide up from behind the tab bar. If you don’t need that, then I’d think you’d use config.presentationContext = .window(...).

@amaurydavid
Copy link
Author

Ah my bad, I made a misstake in my original post.
The SwiftMessage view is presented from the TabbarController, true, but the tabbarController is not the parent, the parent is one UINavigationController used in the tabBarController.
This way the SwiftMessage's view is correctly above the tabBar and doesn't overlap it.

@wtmoose
Copy link
Member

wtmoose commented Oct 21, 2019

Can you use config.presentationContext = .window(...)?

@amaurydavid
Copy link
Author

Unfortunately using a .window() context will make the message overlap the UITabBar which we don't want.
The message should be displayed above the UITabBar.

@MaoDaAmargura
Copy link

I have some more information to add to this issue, maybe it'll help others.

• 7.0.1 does not prevent the crashes.

• I finally managed to reproduce the issue in my debugger. What appears to be happening to me is:

  1. View Controller begins a UIView.animate() { pushViewController(animated:false) custom transition to a TabBarController subclass, that will eventually contain the SwiftMessage.
  2. A (probably unrelated) database failure occurs, which triggers (3)
  3. This causes the view controllers navigation controller to begin a separate UIView.animate() (similar) transition to a different UIViewController.
  4. I believe in the process of creating and rendering both view controllers for the animations, when the SwiftMessage attempts to grab a UITabBar to bind to, (which I assume is through view.window because my presentationContext is .view() ) it grabs the wrong viewController, and gets the TabBar associated with the other view controller.

In this case, fixing the database issue prevented the two animations from playing simultaneously when they shouldn't have, which prevents the issue.

I have released an update with this fix, and will update the thread again if i see any more of these crashes.

@wtmoose
Copy link
Member

wtmoose commented Dec 6, 2019

Thanks for the update. Just be clarify one thing:

presentationContext is .view()

When you use this presentation context, the message is displayed in the view you specify. It doesn’t have any reason to try and find a tab bar.

@MaoDaAmargura
Copy link

Okay, if it doesn't try to find a tab bar through .view, then it would have to be one of my other .viewController() presentation contexts (we use SwiftMessage a lot) that crashed... and I can't explain how it's finding a tabBar reference that's not associated with the viewController that is used as the presentationContext. Unless the fact that its during that animation transition is the problem, but all my SwiftMessages are displayed in viewDidAppear or later. It's a really weird crash.

I honestly would've blamed the crash i could reproduce in XCode (described above) on the database issue, but it crashes in the InstallMaskingView every time. If it was just the database crashing on a background thread, i'd get some different stack traces occasionally.

My version with this fix has been live for 40 hours now, without one of these crashes. That is positive.

@MaoDaAmargura
Copy link

I am still seeing some of these crashes. I'm going to look for other places that SwiftMessages might be created by viewControllers during a custom animated transition.

@MaoDaAmargura
Copy link

I've managed to reproduce this once on my device:

I have some view controllers that can both show a .bottom aligned SwiftMessage and push another view controller in viewDidAppear

In cases where both happen, and the pushed view controller has .hideBottomBarOnPush = true, sometimes there's a timing issue that causes this crash. I'm going to make these items mutually exclusive to prevent this issue.

@wtmoose
Copy link
Member

wtmoose commented Apr 22, 2020

@MaoDaAmargura thanks for sharing your findings!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants