Code Block Crashed Thread: 0 Dispatch queue: com.apple.main-thread Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Application Specific Information: *** Terminating app due to uncaught exception'NSGenericException', reason: 'The window has been marked as needing another Layout Window pass, but it has already had more Layout Window passes than there are views in the window.' terminating with uncaught exception of type NSException abort() called Application Specific Backtrace 1: 0 CoreFoundation 0x00007fff35ab1727 __exceptionPreprocess + 250 1 libobjc.A.dylib 0x00007fff6ea17a9e objc_exception_throw + 48 2 CoreFoundation 0x00007fff35ab1585 +[NSException raise:format:] + 181 3 AppKit 0x00007fff32ce198b -[NSWindow(NSDisplayCycle) _postWindowNeedsLayoutUnlessPostingDisabled] + 1577 4 AppKit 0x00007fff32ce1307 -[NSWindow(NSConstraintBasedLayout) _setViewsNeedLayout:] + 49 5 AppKit 0x00007fff32cb6a5b -[NSView setNeedsLayout:] + 660 6 UIFoundation 0x00007fff66b3305a -[_NSCollectionViewCore setNeedsLayout] + 53 7 UIFoundation 0x00007fff66b32a9a -[_NSCollectionViewCore _invalidateLayoutWithContext:] + 3473 8 UIFoundation 0x00007fff66b31ce5 -[NSCollectionViewLayout invalidateLayoutWithContext:] + 79 9 UIFoundation 0x00007fff66b31ae7 -[NSCollectionViewFlowLayout invalidateLayoutWithContext:] + 1901 10 UIFoundation 0x00007fff66b31367 -[NSCollectionViewLayout invalidateLayout] + 129 11 APTX 0x000000010f6062d3 HomeViewController.configurePhotosCollectionViewAfterResize() (in APTX) (<compiler-generated>:0) 12 APTX 0x000000010f6487b5 HomeViewController.windowDidResize(_:) (in APTX) (<compiler-generated>:0) 13 APTX 0x000000010f6489fd @objc HomeViewController.windowDidResize(_:) (in APTX) + 109 14 CoreFoundation 0x00007fff35a2b259 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12 .... Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 libsystem_kernel.dylib 0x00007fff6fcff33a __pthread_kill + 10 1 libsystem_pthread.dylib 0x00007fff6fdbfe60 pthread_kill + 430 2 libsystem_c.dylib 0x00007fff6fc86808 abort + 120 3 libc++abi.dylib 0x00007fff6ceed458 abort_message + 231 4 libc++abi.dylib 0x00007fff6cede8bf demangling_terminate_handler() + 262 5 libobjc.A.dylib 0x00007fff6ea19a57 _objc_terminate() + 96 6 libc++abi.dylib 0x00007fff6ceec887 std::__terminate(void (*)()) + 8 7 libc++abi.dylib 0x00007fff6ceef387 __cxa_rethrow + 99 8 libobjc.A.dylib 0x00007fff6ea17e1c objc_exception_rethrow + 37 9 com.apple.AppKit 0x00007fff32d79153 __NSWindowGetDisplayCycleObserverForLayout_block_invoke + 577 10 com.apple.AppKit 0x00007fff32d781f2 NSDisplayCycleObserverInvoke + 155 11 com.apple.AppKit 0x00007fff32d77d7c NSDisplayCycleFlush + 937 12 com.apple.QuartzCore 0x00007fff4153ce40 CA::Transaction::run_commit_handlers(CATransactionPhase) + 106 13 com.apple.QuartzCore 0x00007fff4153bb52 CA::Transaction::commit() + 230 14 com.apple.AppKit 0x00007fff32fec726 -[NSMoveHelper _doAnimation] + 64 15 com.apple.AppKit 0x00007fff32feb620 -[NSMoveHelper(NSSheets) _moveParent:andOpenSheet:] + 1448 16 com.apple.AppKit 0x00007fff32feb052 -[NSWindow(NSSheets) _orderFrontRelativeToWindow:] + 164 17 com.apple.AppKit 0x00007fff32df3bb2 -[NSWindow _reallyDoOrderWindowAboveOrBelow:relativeTo:findKey:forCounter:force:isModal:] + 2217 18 com.apple.AppKit 0x00007fff32df2fb2 -[NSWindow _reallyDoOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 135 19 com.apple.AppKit 0x00007fff32df1f3e -[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 293 20 com.apple.AppKit 0x00007fff32f945a9 -[NSApplication _orderFrontModalWindow:relativeToWindow:] + 232 21 com.apple.AppKit 0x00007fff32fea89a -[NSWindow _beginWindowBlockingModalSessionForSheet:service:completionHandler:isCritical:] + 585 22 com.apple.AppKit 0x00007fff33047fd0 __54-[NSAlert beginSheetModalForWindow:completionHandler:]_block_invoke + 281 23 com.apple.AppKit 0x00007fff33044755 -[NSAlert beginSheetModalForWindow:completionHandler:] + 98 24 com.ail.aptxx 0x000000010f62eddf specialized OtherHelper.showAlert(window:title:message:isInformational:arrButtonTitles:responseHandler:) (in APTX) (<compiler-generated>:0) 25 com.ail.aptxx 0x000000010f60fc48 HomeViewController.checkForPhotosAppOpened() (in APTX) (HomeViewController.swift:1408) 26 com.ail.aptxx 0x000000010f603fae HomeViewController.viewWillAppear() (in APTX) (HomeViewController.swift:117) 27 com.ail.aptxx 0x000000010f604428 @objc HomeViewController.viewWillAppear() (in APTX) (<compiler-generated>:0)
Crash in app window resizing code
Looks like you are entering an infinite loop, and system crashes when the number of passes exceed the number of views in the window'The window has been marked as needing another Layout Window pass, but it has already had more Layout Window passes than there are views in the window.'
WindowDidResize Function
(Note that the app has two panes, and on reducing the window width the left (L) pane is hidden - as in Photos for Mac app).
Code Block func windowDidResize(_ notification: Notification) { if let window = self.view.window { let arrScreens = NSScreen.screens if arrScreens.count > 0 { let theScreenRect = arrScreens[0] // Hide the L pane if (theScreenRect.frame.size.width / 3.0) >= window.frame.size.width { window.setFrame(CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: (theScreenRect.frame.size.width / 3.0), height: window.frame.size.height), display: true, animate: true) theSplitView?.arrangedSubviews.first?.isHidden = true if (theSplitView.arrangedSubviews.count) < 2 { theSplitView?.removeArrangedSubview((theSplitView?.arrangedSubviews.first)!) } else { theSplitView = orignalSplitView theSplitView?.arrangedSubviews.first?.setFrameSize(NSSize(width: 250.0, height: window.frame.size.height)) } } else { // Show the L pane window.setFrame(CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.size.width, height: window.frame.size.height), display: true, animate: true) theSplitView = orignalSplitView theSplitView?.arrangedSubviews.first?.setFrameSize(NSSize(width: 250.0, height: window.frame.size.height)) theSplitView?.arrangedSubviews.first?.isHidden = false } // Don't allow to resize if (theScreenRect.frame.size.height / 1.5) >= window.frame.size.height { window.setFrame(CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.size.width, height: (theScreenRect.frame.size.height / 1.5)), display: true, animate: true) } else { // Allow to resize window.setFrame(CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.size.width, height: window.frame.size.height), display: true, animate: true) } configurePhotosCollectionViewAfterResize() }
Configure Photos Collection View
Code Block func configurePhotosCollectionViewAfterResize() { self.collectionViewPhotos.collectionViewLayout?.invalidateLayout() }
These are only two functions being called when the window is resized. If anything else is needed, please let me know. Maybe we need to add something after invalidating the layout? Not sure. Many thanks.
So, I would comment out some parts and see if the problem occurs (of course app will not work perfectly during this, but it is just to find cause of crash.
Comment all out: from line 7 to 52
uncomment lines 7 to 33
uncomment lines 34 to 50
uncomment lines 34 to 50
uncomment lines 51 to 52
Anything you can spot in the crash report that we might have missed? It's EXC_CRASH (SIGABRT), so unhandled language exception or application passing bad data to a system routine? It mentions (<compiler-generated>:0) i.e. crashing in compiled generated code at Line 0? You have already pointed out the crash reason pointing to infinite loop possibility.
Doc for UICollectionViewLayout says:
When designing your custom layouts, you can improve performance by invalidating only those parts of your layout that actually changed. When you change items, calling the invalidateLayout() method forces the collection view to recompute all of its layout information and reapply it. A better solution is to recompute only the layout information that changed, which is exactly what invalidation contexts allow you to do. An invalidation context lets you specify which parts of the layout changed. The layout object can then use that information to minimize the amount of data it recomputes.
So, could you either:
remove this invalidate completely (what happens to your app then ?)
use a more focused invalidate:
Code Block func invalidateLayout(with: UICollectionViewLayoutInvalidationContext)
Invalidates the current layout using the information in the provided context object.instead of
Code Block func invalidateLayout()
Invalidates the current layout and triggers a layout update.relocate the call to configurePhotosCollectionViewAfterResize() in another func
Code Block override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() configurePhotosCollectionViewAfterResize() }
following an idea found here:
https://stackoverflow.com/questions/36884376/swift-how-to-refresh-uicollectionview-layout-after-rotation-of-the-device
Note: could you testFlight your app, or download yourself to test it ? TestFlight would be more appropriate here.
So which was the correct answer in this thread ?