应用程序在调用自定义按钮的 setNeedsDisplay 时崩溃

App crashes on call to setNeedsDisplay for custom button

我有自定义按钮,应用程序在调用 setNeedsDisplay 时随机崩溃。如何修复此崩溃?

class MyVC: UIViewController {

    @IBOutlet weak var customButton: CustomButton!

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        self.customButton.setNeedsDisplay() // Random crash here
    }
}

class CustomButton: UIButton {
    // ....

    override func setNeedsDisplay() {
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: UIScreen.main.bounds.size.width-29, bottom: 4.0, right: 0)
    }
}

崩溃日志

Crashed: com.apple.main-thread EXC_BREAKPOINT 0x0000000104fb3f48

Crashed: com.apple.main-thread 0 myapp 0x104fb3f48 MyVC.viewWillTransition(to:with:) + 63 (MyVC.swift:63) 1 myapp
0x104fb3f88 @objc MyVC.viewWillTransition(to:with:) () 2 UIKitCore 0x1ee286708 -[UIViewController viewWillTransitionToSize:withTransitionCoordinator:] + 868 3 UIKitCore 0x1ee1e596c -[UINavigationController viewWillTransitionToSize:withTransitionCoordinator:] + 84 4 UIKitCore 0x1ee286708 -[UIViewController viewWillTransitionToSize:withTransitionCoordinator:] + 868 5 UIKitCore 0x1ee1b46dc -[UITabBarController viewWillTransitionToSize:withTransitionCoordinator:] + 48 6 UIKitCore 0x1ee27ba18 +[UIViewController _performWithoutDeferringTransitions:] + 112 7 UIKitCore 0x1ee292a24 -[UIViewController(AdaptiveSizing) _window:viewWillTransitionToSize:withTransitionCoordinator:] + 580 8 UIKitCore 0x1ee8537c4 59-[UIWindow _rotateToBounds:withAnimator:transitionContext:]_block_invoke + 188 9 UIKitCore 0x1eeca08f0 +[UIView(Animation) performWithoutAnimation:] + 104 10 UIKitCore
0x1ee853618 -[UIWindow _rotateToBounds:withAnimator:transitionContext:] + 412 11 UIKitCore 0x1ee855e24 -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] + 1184 12 UIKitCore 0x1ee8564d8 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 516 13 UIKitCore 0x1ee8558d8 -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 128 14 UIKitCore 0x1ee854584 __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 124 15 UIKitCore 0x1ee854488 -[UIWindow _updateToInterfaceOrientation:duration:force:] + 560 16 UIKitCore 0x1ee0dcfe0 -[_UICanvasMetricsCalculator updateMetricsOnWindows:animated:] + 624 17 UIKitCore
0x1ee0e1990 -[_UICanvas _computeMetrics:] + 180 18 UIKitCore
0x1eeca08f0 +[UIView(Animation) performWithoutAnimation:] + 104 19 UIKitCore 0x1ee0e04a8 -[_UICanvas _performActions:withOverrideSettings:] + 172 20 UIKitCore 0x1ee821b0c -[UIApplication _createSnapshotContextForScene:withName:performLayoutWithSettings:] + 404 21 UIKitCore 0x1ee8232f0 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_2 + 124 22 FrontBoardServices 0x1c4b51768 -[FBSSceneSnapshotAction _executeNextRequest] + 256 23 FrontBoardServices 0x1c4b517b8 -[FBSSceneSnapshotAction _executeNextRequest] + 336 24 FrontBoardServices 0x1c4b51358 -[FBSSceneSnapshotAction executeRequestsWithHandler:completionHandler:expirationHandler:] + 276 25 UIKitCore 0x1ee823220 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke + 268 26 UIKitCore 0x1ee822848 -[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:] + 744 27 UIKitCore 0x1ee822f74 -[UIApplication _performSnapshotsWithAction:forScene:completion:] + 208 28 UIKitCore 0x1ee822e40 -[UIApplication _handleSnapshotAction:forScene:completion:] + 156 29 UIKitCore 0x1ee81e724 __71-[UIApplication _handleSnapshotAction:forScene:deactivationCompletion:]_block_invoke + 332 30 UIKitCore 0x1ee81e540 -[UIApplication _handleSnapshotAction:forScene:deactivationCompletion:] + 340 31 UIKitCore 0x1ee0d9f58 __98-[__UICanvasLifecycleMonitor_Compatability deactivateEventsOnly:withContext:forceExit:completion:]_block_invoke.261 + 820 32 UIKitCore 0x1ee8220ac _runAfterCACommitDeferredBlocks + 296 33 UIKitCore 0x1ee810bfc _cleanUpAfterCAFlushAndRunDeferredBlocks + 352 34 UIKitCore 0x1ee83da6c _afterCACommitHandler + 116 35 CoreFoundation 0x1c212ed08 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
+ 32 36 CoreFoundation 0x1c2129a30 __CFRunLoopDoObservers + 412 37 CoreFoundation 0x1c2129fac __CFRunLoopRun + 1228 38 CoreFoundation 0x1c21297c0 CFRunLoopRunSpecific + 436 39 GraphicsServices
0x1c432a79c GSEventRunModal + 104 40 UIKitCore
0x1ee816c38 UIApplicationMain + 212 41 myapp
0x104db7454 main + 20 (ProfileVC.swift:20) 42 libdyld.dylib
0x1c1bed8e0 start + 4

假设您的崩溃行实际上应该是:

self.customButton.setNeedsDisplay() // Random crash here

问题很可能是customButton为零。您已将 customButton 声明为隐式展开的可选。这意味着当您尝试引用它时,编译器会为您解包。尝试添加:

print("self.customButton = \(self.customButton?)")
self.customButton.setNeedsDisplay() // Random crash here

并查看调试日志。我猜你会看到类似的东西:

self.customButton = Optional(nil)