Crash - NSLayoutConstraint constant is not finite!
haffez23 opened this issue · 6 comments
I logged a crash in my firebase console, it happned for one user 3 times and I cant reproduce it Here
Environment
- Device: iPhone 13 Pro
- iOS version: 16
- Instructions version: main
- Dependency Manager: CocoaPods
Trace of crash:
Fatal Exception: NSInternalInconsistencyException
NSLayoutConstraint constant is not finite! That's illegal. constant:inf firstAnchor:<NSLayoutYAxisAnchor:0x283d7fd80 "Instructions.CoachMarkView:0x11ffb0050.bottom"> secondAnchor:<NSLayoutYAxisAnchor:0x283db3840
"Instructions.InstructionsRootView:0x11ffa7ab0.bottom">
Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0xa248 __exceptionPreprocess
1 libobjc.A.dylib 0x17a68 objc_exception_throw
2 Foundation 0x54681c _userInfoForFileAndLine
3 CoreAutoLayout 0xb8e4 -[NSLayoutConstraint _setSymbolicConstant:constant:symbolicConstantMultiplier:]
4 CoreAutoLayout 0x1574 -[NSLayoutConstraint setConstant:]
5 CoreAutoLayout 0x1324 +[NSLayoutConstraint constraintWithAnchor:relatedBy:toAnchor:multiplier:constant:]
6 Instructions 0xfa80 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
7 Instructions 0xe868 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
8 Instructions 0x16b84 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
9 Instructions 0x19f44 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
10 Instructions 0x192a0 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
11 Instructions 0x166e8 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
12 Instructions 0x20bc8 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
13 Instructions 0x204e0 (Manquant UUID e5aa90ad73623213b26ec3ed2d547935)
14 UIKitCore 0x10251b0 UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK
15 UIKitCore 0xd2114 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:]
16 UIKitCore 0xd1070 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
17 UIKitCore 0xd0790 -[UIViewAnimationState animationDidStop:finished:]
18 QuartzCore 0x13ae8 CA::Layer::run_animation_callbacks(void*)
19 libdispatch.dylib 0x3fdc dispatch_client_callout
20 libdispatch.dylib 0x127f4 dispatch_main_queue_drain
21 libdispatch.dylib 0x12444 dispatch_main_queue_callback_4CF
22 CoreFoundation 0x9aa08 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
23 CoreFoundation 0x7c368 __CFRunLoopRun
24 CoreFoundation 0x811e4 CFRunLoopRunSpecific
25 GraphicsServices 0x1368 GSEventRunModal
26 UIKitCore 0x3a2d88 -[UIApplication run]
27 UIKitCore 0x3a29ec UIApplicationMain
28 libswiftUIKit.dylib 0x352a0 UIApplicationMain(::::)
22 MYAPP 0xdfcc main + 4371423180 (MF.swift:4371423180)
23 ??? 0x1be3bd948 (Manquant)
Happens to my users as well, any ETA on a fix?
Added Symbolic Breakpoint "CGPostError" and captured the stacktrace. Also attaching the crash log downloaded from TestFlight. crashlog.txt
- thread 1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
- frame 0: 0x00000001d1d1c97c CoreGraphics
CGPostError frame 1: 0x00000001d1c81e20 CoreGraphics
CGFloatValidateWithLog + 148
frame 2: 0x00000001d1c4bb64 CoreGraphicsCGPathAddLineToPoint + 92 frame 3: 0x00000001d243284c UIKitCore
+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadii:segments:smoothPillShapes:] + 1192
frame 4: 0x00000001d2432344 UIKitCore+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadius:segments:] + 184 frame 5: 0x00000001d2431f14 UIKitCore
+[UIBezierPath _roundedRectBezierPath:withRoundedCorners:cornerRadius:segments:legacyCorners:] + 344
frame 6: 0x000000010347f6fc CLSS QA@nonobjc UIBezierPath.__allocating_init(roundedRect:byRoundingCorners:cornerRadii:) at <compiler-generated>:0 frame 7: 0x000000010347e604 CLSS QA
CoachMarkHelper.update(coachMark=Instructions.CoachMark @ 0x000000016d348e90, frame=(origin = (x = 0, y = 0), size = (width = 597, height = 54)), pointOfInterest=nil, superview=0x000000010a68f290, cutoutPathMaker=nil, self=0x0000000281721ad0) at CoachMarkHelper.swift:285:30
frame 8: 0x000000010347e1c4 CLSS QACoachMarkHelper.makeCoachMark(view=0x000000010a68f630, pointOfInterest=nil, cutoutPathMaker=nil, self=0x0000000281721ad0) at CoachMarkHelper.swift:108:9 frame 9: 0x000000010339a3e8 CLSS QA
FMCoachMarksManager.coachMarksController(coachMarksController=0x00000002832f1ea0, index=0, self=0x0000000281ee2080) at FMCoachMarksManager.swift:64:53
frame 10: 0x000000010339c050 CLSS QAprotocol witness for CoachMarksControllerDataSource.coachMarksController(_:coachMarkAt:) in conformance FMCoachMarksManager at <compiler-generated>:0 frame 11: 0x00000001034643c4 CLSS QA
CoachMarksController.coachMark(index=0, self=0x00000002832f1ea0) at CoachMarksController+Proxy.swift:12:28
frame 12: 0x0000000103464668 CLSS QAprotocol witness for CoachMarksControllerProxyDataSource.coachMark(at:) in conformance CoachMarksController at <compiler-generated>:0 frame 13: 0x0000000103491164 CLSS QA
FlowManager.createAndShowCoachMark(afterResuming=false, change=nothing, self=0x0000000282eb48f0) at FlowManager.swift:204:49
frame 14: 0x00000001034903ac CLSS QAFlowManager.showNextCoachMark(hidePrevious=true, self=0x0000000282eb48f0) at FlowManager.swift:125:13 frame 15: 0x000000010348f644 CLSS QA
closure 1 in FlowManager.startFlow(self=0x0000000282eb48f0) at FlowManager.swift:66:18
frame 16: 0x000000010345baf8 CLSS QAclosure 1 in CoachMarksViewController.prepareToShowCoachMarks(_0=true, self=0x00000001148a6400, completion=0x000000010348f654 CLSS QA
partial apply forwarder for closure 1 () -> () in Instructions.FlowManager.startFlow(withNumberOfCoachMarks: Swift.Int) -> () at ) at CoachMarksViewController.swift:258:13
frame 17: 0x000000010348a8c8 CLSS QAclosure 2 in TranslucentOverlayStyleManager.showOverlay(success=true, show=true, self=0x0000000280cb5580, overlay=0x000000010a689330, completion=0x000000010345dddc CLSS QA
partial apply forwarder for closure 1 (Swift.Bool) -> () in Instructions.CoachMarksViewController.prepareToShowCoachMarks(() -> ()) -> () at ) at TranslucentOverlayStyleManager.swift:77:23
frame 18: 0x000000010348298c CLSS QAthunk for @escaping @callee_guaranteed (@unowned Bool) -> () at <compiler-generated>:0 frame 19: 0x00000001d3292464 UIKitCore
UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK + 36
frame 20: 0x00000001d23264ac UIKitCore-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 636 frame 21: 0x00000001d2325408 UIKitCore
-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 436
frame 22: 0x00000001d2324b28 UIKitCore-[UIViewAnimationState animationDidStop:finished:] + 196 frame 23: 0x00000001d173610c QuartzCore
CA::Layer::run_animation_callbacks(void*) + 232
frame 24: 0x00000001061ea05c libdispatch.dylib_dispatch_client_callout + 20 frame 25: 0x00000001061fa810 libdispatch.dylib
_dispatch_main_queue_drain + 1196
frame 26: 0x00000001061fa354 libdispatch.dylib_dispatch_main_queue_callback_4CF + 44 frame 27: 0x00000001d011a6d8 CoreFoundation
CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 16
frame 28: 0x00000001d00fc03c CoreFoundation__CFRunLoopRun + 2036 frame 29: 0x00000001d0100ec0 CoreFoundation
CFRunLoopRunSpecific + 612
frame 30: 0x00000002098ab368 GraphicsServicesGSEventRunModal + 164 frame 31: 0x00000001d25f686c UIKitCore
-[UIApplication _run] + 888
frame 32: 0x00000001d25f64d0 UIKitCoreUIApplicationMain + 340 frame 33: 0x0000000102b403fc CLSS QA
main(argc=1, argv=0x000000016d34b6c8) at main.m:16:16
frame 34: 0x00000001ee912960 dyld`start + 2528
- frame 0: 0x00000001d1d1c97c CoreGraphics
seeing this on an iPhone 11 running 16.2
Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x9e48 __exceptionPreprocess
1 libobjc.A.dylib 0x178d8 objc_exception_throw
2 Foundation 0x54594c _userInfoForFileAndLine
3 CoreAutoLayout 0xb8e4 -[NSLayoutConstraint _setSymbolicConstant:constant:symbolicConstantMultiplier:]
4 CoreAutoLayout 0x1574 -[NSLayoutConstraint setConstant:]
5 CoreAutoLayout 0x1324 +[NSLayoutConstraint constraintWithAnchor:relatedBy:toAnchor:multiplier:constant:]
6 Instructions 0xdd48 specialized CoachMarkDisplayManager.generateAndEnableVerticalConstraints(of:forDisplayIn:usingCoachMark:cutoutPath:andOverlayView:) + 256 (CoachMarkDisplayManager.swift:256)
7 Instructions 0xcb84 CoachMarkDisplayManager.showNew(coachMarkView:from:at:animated:completion:) (<compiler-generated>)
8 Instructions 0xae44 CoachMarksViewController.show(coachMark:at:animated:completion:) + 291 (CoachMarksViewController.swift:291)
9 Instructions 0x1baf4 FlowManager.createAndShowCoachMark(afterResuming:changing:) + 221 (FlowManager.swift:221)
10 Instructions 0x1ae48 FlowManager.showNextCoachMark(hidePrevious:) + 178 (FlowManager.swift:178)
11 Instructions 0xa9bc closure #1 in CoachMarksViewController.prepareToShowCoachMarks(_:) + 259 (CoachMarksViewController.swift:259)
12 Instructions 0x12094 closure #2 in TranslucentOverlayStyleManager.showOverlay(_:withDuration:completion:) + 78 (TranslucentOverlayStyleManager.swift:78)
13 Instructions 0x1d130 thunk for @escaping @callee_guaranteed (@unowned Bool) -> () (<compiler-generated>)
14 UIKitCore 0x103d464 __UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__
15 UIKitCore 0xd14ac -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:]
16 UIKitCore 0xd0408 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
17 UIKitCore 0xcfb28 -[UIViewAnimationState animationDidStop:finished:]
18 QuartzCore 0x1310c CA::Layer::run_animation_callbacks(void*)
19 libdispatch.dylib 0x3fdc _dispatch_client_callout
20 libdispatch.dylib 0x127f4 _dispatch_main_queue_drain
21 libdispatch.dylib 0x12444 _dispatch_main_queue_callback_4CF
22 CoreFoundation 0x9a6d8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
23 CoreFoundation 0x7c03c __CFRunLoopRun
24 CoreFoundation 0x80ec0 CFRunLoopRunSpecific
25 GraphicsServices 0x1368 GSEventRunModal
26 UIKitCore 0x3a186c -[UIApplication _run]
27 UIKitCore 0x3a14d0 UIApplicationMain
28 App 0x9340 main + 35 (*.swift:35)
29 ??? 0x1a9aba960 (Missing)
Thanks for all the crash reports! It's a peculiar bug. Here's the code in question:
private func generateAndEnableVerticalConstraints(of coachMarkView: CoachMarkView,
forDisplayIn parentView: UIView,
usingCoachMark coachMark: CoachMark,
cutoutPath: UIBezierPath,
andOverlayView overlayView: OverlayView) {
let offset = coachMark.gapBetweenCoachMarkAndCutoutPath
// Depending where the cutoutPath sits, the coach mark will either
// stand above or below it. Alternatively, it can also be displayed
// over the cutoutPath.
if coachMark.isDisplayedOverCutoutPath {
…
} else if coachMark.arrowOrientation! == .bottom {
let constant = -(parentView.frame.size.height - cutoutPath.bounds.origin.y + offset)
// This is the call that triggers the crash.
coachMarkView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor,
constant: constant).isActive = true
} else {
…
}
}
For constant
to be infinite, any of parentView.frame.size.height
, cutoutPath.bounds.origin.y
, or offset
must be infinite. I can't think of a scenario where this would be the case, I don't think UIView frames can ever be infinite, so I guess the culprit is cutoutPath
.
It would help to know how cutoutPath
is generated on your end!
@ephread I just had a user report the same issue. The crash report shows the crash happening at the location you pointed to. I can't get it to crash at all on my device or any iOS simulators. The user has an iPhone 13 Pro Max running the 16.5 beta. I thought the beta was the issue but the crash is happening exactly where the other users are reporting it;
if coachMark.isDisplayedOverCutoutPath {
let constant = cutoutPath.bounds.midY - parentView.frame.size.height / 2
coachMarkView.centerYAnchor.constraint(equalTo: parentView.centerYAnchor,
constant: constant).isActive = true
} else if coachMark.arrowOrientation! == .bottom {
let constant = -(parentView.frame.size.height -
cutoutPath.bounds.origin.y + offset)
coachMarkView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor,
constant: constant).isActive = true
} else {
let constant = (cutoutPath.bounds.origin.y +
cutoutPath.bounds.size.height) + offset
coachMarkView.topAnchor.constraint(equalTo: parentView.topAnchor,
constant: constant).isActive = true
}
}
I am only using one custom cutout;
func coachMarksController(_ coachMarksController: CoachMarksController,
coachMarkAt index: Int) -> CoachMark {
switch index {
case 0:
return coachMarksController.helper.makeCoachMark(
for: self.navigationController?.navigationBar,
cutoutPathMaker: { (frame: CGRect) -> UIBezierPath in
// This will make a cutoutPath matching the shape of
// the component (no padding, no rounded corners).
return UIBezierPath(rect: frame)
}
)
case 1:
return coachMarksController.helper.makeCoachMark(
for: self.leftStackOutlet,
cutoutPathMaker: { (frame: CGRect) -> UIBezierPath in
return UIBezierPath(rect: CGRect(x: 0, y: self.leftStackOutlet.frame.origin.y, width: self.view.frame.width, height: self.leftStackOutlet.frame.height))
}
)
case 2:
return coachMarksController.helper.makeCoachMark(for: self.allShortcutsOutlet)
default:
return coachMarksController.helper.makeCoachMark()
}
}
I managed to reproduce this issue, and get around it; maybe the same approach works for others too.
I was able to reproduce this issue by presenting a coachmark while mirroring screen from my iPhone to my Mac. At that point, there are two scenes, two windows & two screens. It's a bit tricky to debug at that point, since screen mirroring doesn't allow switching to Xcode; you have to cancel screen mirroring at the moment when you have your breakpoints ready.
I was presenting a coachmark using PresentationContext.newWindow(over:at:)
, because of which a new window was created to handle this presentation.
The original cause of this crash is within buildNewWindow()
method, because it created a window on a scene that's connected to my Mac's monitor, instead on the iPhone's screen's scene. However, the issue with infinite constant is caused specifically by convert(rect:from)
method of CoachMarkCoordinateConverter
.
When calling:
let rectInInstructionsWindow = instructionsWindow.convert(rectInWindow,
from: superviewWindow)
rectInInstructionsWindow
ends up being CGRect.zero
, and there's a log in the console about this issue.
I fixed the issue for myself by presenting a coachmark using PresentationContext.viewController(_:)
.