Crash: PinLayout.swift - Line 1236
orojasnypost opened this issue · 7 comments
Firebase crashlytics is reporting that our app is crashing after PinLayout
tries to call referenceSuperview
and this method calls viewDescription
. It seems that the object referenceView
which should be created from anchor.view
in the method computeCoordinatesForAnchors
in the line 384 of PinLayout+Coordinates
is nil. And this causes referenceSuperview
to fail to create a reference to the superview from referenceView.superview
. Because of this when warnWontBeApplied
is called in line 1236 of PinLayout
crashes when it tries to call viewDescription(referenceView)
This is the stacktrace from crashlytics:
Crashed: com.apple.main-thread
0 libswiftCore.dylib 0x3da990 swift_getObjectType + 40
1 PinLayout 0x2557c PinLayout.viewDescription(_:) + 4375287164 (<compiler-generated>:4375287164)
2 PinLayout 0xb684 PinLayout.referenceSuperview(_:_:) + 1236 (PinLayout.swift:1236)
3 PinLayout 0x101b4 closure #1 in PinLayout.computeCoordinates(forAnchors:_:) + 384 (PinLayout+Coordinates.swift:384)
4 PinLayout 0xfdb8 PinLayout.computeCoordinates(forAnchors:_:) + 4375199160 (<compiler-generated>:4375199160)
5 PinLayout 0x1987c PinLayout.below(of:aligned:context:) + 170 (PinLayout+Relative.swift:170)
6 PinLayout 0x19e30 PinLayout.above(of:aligned:) + 4375240240
7 NYP 0x2b9fd4 NYPVerticalContainerFrameView.layout() + 92 (NYPVerticalContainerFrameView.swift:92)
8 NYP 0x2ba9a4 protocol witness for FrameViewProtocol.layout() in conformance NYPVerticalContainerFrameView + 4334070180 (<compiler-generated>:4334070180)
9 NYP 0x6f7e48 FrameViewProtocol<>.heightThatFits(_:) + 43 (FrameViewType.swift:43)
10 NYP 0x26b3ac NYPVerticalContainerFrame.height(forWidth:) + 91 (NYPVerticalContainerFrame.swift:91)
11 NYP 0x654360 ContainerCollectionViewLayout.attributesFor(frame:currentXOffset:currentYOffset:indexPath:inRow:) + 47 (Container+LayoutHelpers.swift:47)
12 NYP 0x65b068 calculateAttributes #1 (for:) in attemptToLayout #1 (frame:atIndex:) in ContainerCollectionViewLayout.prepare() + 447 (ContainerCollectionViewLayout.swift:447)
13 NYP 0x65a1d4 attemptToLayout #1 (frame:atIndex:) in ContainerCollectionViewLayout.prepare() + 472 (ContainerCollectionViewLayout.swift:472)
14 NYP 0x655ec0 ContainerCollectionViewLayout.prepare() + 498 (ContainerCollectionViewLayout.swift:498)
15 NYP 0x65bee8 @objc ContainerCollectionViewLayout.prepare() + 4337876712 (<compiler-generated>:4337876712)
16 UIKitCore 0x174154 -[UICollectionViewData _prepareToLoadData] + 200
17 UIKitCore 0x176b4c -[UICollectionViewData validateLayoutInRect:] + 96
18 UIKitCore 0x179be8 -[UICollectionView layoutSubviews] + 220
19 UIKitCore 0x18c17c -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2592
20 QuartzCore 0x407fc CA::Layer::layout_if_needed(CA::Transaction*) + 532
21 QuartzCore 0x32c60 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 136
22 QuartzCore 0x475b4 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 452
23 QuartzCore 0x504a8 CA::Transaction::commit() + 704
24 QuartzCore 0x323a0 CA::Transaction::flush_as_runloop_observer(bool) + 88
25 UIKitCore 0x53e6e0 _UIApplicationFlushCATransaction + 72
26 UIKitCore 0x7d8d5c _UIUpdateSequenceRun + 84
27 UIKitCore 0xe5fedc schedulerStepScheduledMainSection + 144
28 UIKitCore 0xe5f6a4 runloopSourceCallback + 92
29 CoreFoundation 0xbb414 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
30 CoreFoundation 0xcc1a0 __CFRunLoopDoSource0 + 208
31 CoreFoundation 0x5694 __CFRunLoopDoSources0 + 268
32 CoreFoundation 0xb05c __CFRunLoopRun + 828
33 CoreFoundation 0x1ebc8 CFRunLoopRunSpecific + 600
34 GraphicsServices 0x1374 GSEventRunModal + 164
35 UIKitCore 0x514b58 -[UIApplication _run] + 1100
36 UIKitCore 0x296090 UIApplicationMain + 364
37 NYP 0x66f8 main + 24 (NYPMediaCoder.swift:24)
38 ??? 0x10392dda4 (Missing)
I'm trying to figure out what is causing the issue.
We are doing something like this:
var margin = viewModel.margins
var height: CGFloat = 0.0
for (n, uiView) in frameView.enumerated() {
if n == 0 {
uiView.pin.top(margin).horizontally(margin).height(height)
} else {
let previousView = frameView[n - 1]
if n == frameView.count - 1 {
uiView.pin.below(of: previousView).bottom(margin).horizontally(margin).height(height)
} else {
uiView.pin.below(of: previousView).horizontally(margin).height(height)
}
}
}
According to the data from the stacktrace: NYPVerticalContainerFrameView.layout() + 92
Is the line if n == frameView.count - 1 { ...
but I think the crash is being caused by line 93 which is:
uiView.pin.below(of: previousView).bottom(margin).horizontally(margin).height(height)
Any insights into this?
@orojasnypost, the method referenceSuperview()
is trying to show you a warning that the view don't have a superview
, which means that the view you are trying to layout has not been added yet to another view, so PinLayout is unable to layout it.
I can't explain why it crashes in viewDescription
, but adding the view you are layouting to a superview should fix your issue.
internal func referenceSuperview(_ referenceView: PinView, _ context: Context) -> PinView? {
if let superview = referenceView.superview {
return superview as? PinView
} else {
warnWontBeApplied("the reference view \(viewDescription(referenceView)) must be added as a sub-view before being used as a reference.", context)
return nil
}
}
Also, normally PinLayout's warnings shouldn't be generated in release builds because Pin.logWarnings
is false in release mode. Are you testing a DEBUG build?
internal func warnWontBeApplied(_ text: String, _ context: Context) {
guard Pin.logWarnings else { return }
warn("\(context()) won't be applied, \(text)")
}
@orojasnypost, the method
referenceSuperview()
is trying to show you a warning that the view don't have asuperview
, which means that the view you are trying to layout has not been added yet to another view, so PinLayout is unable to layout it.I can't explain why it crashes in
viewDescription
, but adding the view you are layouting to a superview should fix your issue.internal func referenceSuperview(_ referenceView: PinView, _ context: Context) -> PinView? { if let superview = referenceView.superview { return superview as? PinView } else { warnWontBeApplied("the reference view \(viewDescription(referenceView)) must be added as a sub-view before being used as a reference.", context) return nil } }
We are adding the view we are layouting to the superView, all subviews are added to the superview before layouting. That's why I reached out for solutions and created this issue, because I don't have an idea of why is the referenceView nil but something is happening inside PinLayout IMHO because we aren't doing anything unusual, we use pinLayout regularly in all our views but this is the one that is reporting a problem in firebase.
Also, normally PinLayout's warnings shouldn't be generated in release builds because
Pin.logWarnings
is false in release mode. Are you testing a DEBUG build?internal func warnWontBeApplied(_ text: String, _ context: Context) { guard Pin.logWarnings else { return } warn("\(context()) won't be applied, \(text)") }
Crashlytics is only generating a crash report with this title:
<compiler-generated> line 2147483647
If you check the stack trace I shared above you'll see that it reports the crash here in frame 1:
Crashed: com.apple.main-thread
0 libswiftCore.dylib 0x3da990 swift_getObjectType + 40
1 PinLayout 0x2557c PinLayout.viewDescription(_:) + 4375287164 (:4375287164)
I came to the conclusion that the crash is ocurring there after debugging with breakpoints. But we aren't receiving any warning, this is in production code. Not a Debug build.
-
If you are able to reproduce the issue, you could check in your loop
for (n, uiView) in frameView.enumerated()
that all your view'ssuperview
are valid. -
Check that all views layout and update are done on the main thread.
-
Check you don't set
Pin.logWarnings
totrue
anywhere on your code.
We have never encountered this issue before, its really strange 🤔
Thanks for your help.
- All views and layout updating is done in the main thread.
- Pin.logWarnings = true is nowhere in our code
- I tried validating that the superView of the previous view isn't nil before pinning it. Now we'll have to wait until the fix is released and see if it fixes the crash. Thank you!
Good, for now I will close the issue, if the issue persist you could reopen it later