Hi everyone,
I'm encountering an intermittent crash on iOS 18 only (not reproducible locally, reported in Firebase Crashlytics) at transitionContext.completeTransition(!transitionContext.transitionWasCancelled) within my custom UIViewControllerAnimatedTransitioning. The same code runs fine on iOS 16 and 17 (no Crashlytics report for those iOS version) Here's the crash log:
Crashed: com.apple.main-thread
0 libswiftCore.dylib 0x4391f0 swift_getObjectType + 40
1 ROOM 0x490c48 ItemDetailAnimator.navigationController(_:animationControllerFor:from:to:) + 47 (ItemDetailAnimator.swift:47)
2 ROOM 0x490f3c @objc ItemDetailAnimator.navigationController(_:animationControllerFor:from:to:) + 92 (<compiler-generated>:92)
3 UIKitCore 0xa2d7a4 -[UINavigationController _customTransitionController:] + 516
4 UIKitCore 0x2e51dc -[UINavigationController _immediatelyApplyViewControllers:transition:animated:operation:] + 2620
5 UIKitCore 0x1541d4 __94-[UINavigationController _applyViewControllers:transition:animated:operation:rescheduleBlock:]_block_invoke + 100
6 UIKitCore 0x150768 -[UINavigationController _applyViewControllers:transition:animated:operation:rescheduleBlock:] + 776
7 UIKitCore 0x2e7e44 -[UINavigationController pushViewController:transition:forceImmediate:] + 544
8 UIKitCore 0x2e4230 -[UINavigationController pushViewController:animated:] + 444
9 ROOM 0x66cb04 UINavigationController.pushViewController(_:animated:completion:) + 185 (UINavigationController+Room.swift:185)
10 ROOM 0x8cef4c ItemDetailCoordinator.start(animated:completion:) + 99 (ItemDetailCoordinator.swift:99)
11 ROOM 0xc6c95c protocol witness for Coordinator.start(animated:completion:) in conformance BaseCoordinator + 24 (<compiler-generated>:24)
12 ROOM 0x8ca520 AppCoordinator.startCoordinator(_:url:reference:animated:completion:) + 729 (AppCoordinator.swift:729)
13 ROOM 0x8cb248 protocol witness for URLSupportCoordinatorOpener.startCoordinator(_:url:reference:animated:completion:) in conformance AppCoordinator + 48 (<compiler-generated>:48)
14 ROOM 0xd6166c URLSupportCoordinatorOpener<>.open(url:openingController:reference:animated:completion:) + 118 (URLSupportedCoordinator.swift:118)
15 ROOM 0xc56038 RRAppDelegate.handleURL(url:completion:) + 588 (RRAppDelegate.swift:588)
16 ROOM 0xc502d0 RRAppDelegate.applicationDidBecomeActive(_:) + 330 (RRAppDelegate.swift:330)
17 ROOM 0xc5041c @objc RRAppDelegate.applicationDidBecomeActive(_:) + 52 (<compiler-generated>:52)
18 UIKitCore 0x1fb048 -[UIApplication _stopDeactivatingForReason:] + 1368
My animateTransition code is:
```func animateTransition(
using transitionContext: UIViewControllerContextTransitioning) {
guard let (fromView, toView, fromVC, toVC)
= filterTargets(context: transitionContext) else {
transitionContext.cancelInteractiveTransition()
transitionContext.completeTransition(false)
return
}
let containerView = transitionContext.containerView
toView.frame = transitionContext.finalFrame(for: toVC)
guard let targetView = fromVC.animationTargetView,
let fromFrame = fromVC.animationTargetFrame,
let toFrame = toVC.animationTargetFrame
else {
containerView.insertSubview(toView, aboveSubview: fromView)
toView.frame = transitionContext.finalFrame(for: toVC)
transitionContext.completeTransition(true)
return
}
let newFromFrame = fromView.convert(fromFrame, to: containerView)
let tempImageView: UIImageView
if let target = targetView as? UIImageView,
let image = targetImage ?? target.image,
image.size.height != 0,
target.frame.height != 0,
image.size.width / image.size.height != target.frame.width / target.frame.height {
targetImage = image
tempImageView = UIImageView(image: image)
tempImageView.frame = newFromFrame
tempImageView.contentMode = .scaleAspectFit
} else {
tempImageView = targetView.room.asImageView()
tempImageView.frame = newFromFrame
}
targetView.isHidden = true
let tempFromView = containerView.room.asImageView()
targetView.isHidden = false
let tempHideView = UIView()
containerView.addSubview(tempFromView)
containerView.insertSubview(toView, aboveSubview: tempFromView)
tempHideView.backgroundColor = .white
toView.addSubview(tempHideView)
containerView.addSubview(tempImageView)
//Minus with item detail view y position
//Need to minus navigation bar height of item detail view
var tempHideViewFrame = toFrame
tempHideViewFrame.origin.y -= toView.frame.origin.y
tempHideView.frame = tempHideViewFrame
let duration = transitionDuration(using: transitionContext)
toView.alpha = 0
UIView.animate(withDuration: duration * 0.5, delay: duration * 0.5, options: .curveLinear, animations: {
toView.alpha = 1
})
let scale: CGFloat = toFrame.width / newFromFrame.width
let newFrame = CGRect(
x: toFrame.minX - newFromFrame.minX * scale,
y: toFrame.minY - newFromFrame.minY * scale,
width: tempFromView.frame.size.width * scale,
height: tempFromView.frame.size.height * scale)
UIView.animate(withDuration: duration, delay: 0.0, options: [.curveEaseInOut], animations: {
tempFromView.frame = newFrame
tempImageView.frame = toFrame
}, completion: { _ in
tempHideView.removeFromSuperview()
tempFromView.removeFromSuperview()
tempImageView.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}