Swift NSAnimationContext在被观察者调用时崩溃

Swift NSAnimationContext在被观察者调用时崩溃,swift,macos,core-graphics,core-animation,nsanimationcontext,Swift,Macos,Core Graphics,Core Animation,Nsanimationcontext,我有两个网络视图:webView和customizerWebView。这两个WKWebView都由尾部约束附着。基本上,当我转到菜单并单击“Show Customizer”showCustomizer()或“Hide Customizer”hideCustomizer(),它会调用相应的函数,并显示或隐藏与customizerWebView相关的所有内容 为了澄清这一点,当从附加的NSMenuItems调用这些函数时,一切都会按预期工作并设置动画。但是,当从本质上检测到URL的观察者调用show

我有两个网络视图:
webView
customizerWebView
。这两个WKWebView都由尾部约束附着。基本上,当我转到菜单并单击“Show Customizer”
showCustomizer()
或“Hide Customizer”
hideCustomizer()
,它会调用相应的函数,并显示或隐藏与
customizerWebView
相关的所有内容

为了澄清这一点,当从附加的
NSMenuItems
调用这些函数时,一切都会按预期工作并设置动画。但是,当从本质上检测到URL的观察者调用
show/hideCustomizer()
时,即
URL.contains(“#close”)
,应用程序在
animator()
代码的第一行崩溃,错误为:
致命错误:在隐式展开可选值时意外发现nil

ViewController.swift

import Cocoa
import WebKit

class ViewController: NSViewController, WKUIDelegate, WKNavigationDelegate {
    var customizerURLObserver: NSKeyValueObservation?

    @IBOutlet var webView: WKWebView!
    @IBOutlet var customizerWebView: WKWebView!
    @IBOutlet var rightConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad
        ...
        customizerURLObserver = customizerWebView.observe(\.url, options: .new) { webView, change in
            let url = "\(String(describing: change.newValue))"
            ViewController().urlDidChange(urlString: url) }
    }

    func urlDidChange(urlString: String) {
        let url = cleanURL(urlString)
        if url.contains("#close") { hideCustomizer() }  // Observer call to hide function
    }

    @IBAction func showCustomizerMenu(_ sender: Any) { showCustomizer() }  // These work flawlessly
    @IBAction func hideCustomizerMenu(_ sender: Any) { hideCustomizer() }  // These work flawlessly

    func showCustomizer() {
        let customTimeFunction = CAMediaTimingFunction(controlPoints: 5/6, 0.2, 2/6, 0.9)
        NSAnimationContext.runAnimationGroup({(_ context: NSAnimationContext) -> Void in
            context.timingFunction = customTimeFunction
            context.duration = 0.3
            rightConstraint.animator().constant = 280
            customizerWebView.animator().isHidden = false
            webView.animator().alphaValue = 0.6
        }, completionHandler: {() -> Void in
        })
    }

    func hideCustomizer() {
        let customTimeFunction = CAMediaTimingFunction(controlPoints: 5/6, 0.2, 2/6, 0.9)
        NSAnimationContext.runAnimationGroup({(_ context: NSAnimationContext) -> Void in
            context.timingFunction = customTimeFunction
            context.duration = 0.3
            webView.animator().alphaValue = 1     // Found nil crash highlights this line
            rightConstraint.animator().constant = 0
        }, completionHandler: {() -> Void in
            self.customizerWebView.isHidden = true
        })
    }
}
有人能告诉我为什么这个动画在从NSMenu调用时看起来和工作完美100次,但在从Observer函数调用一次时崩溃吗

我还尝试调用NSMenu对象函数hideCustomizerMenu(self),但无效。

在线:

ViewController().urlditchange(urlString:url)
您错误地创建了视图控制器类的新实例,并对该实例调用了
urlditchange
。因为这个新实例不是从故事板/xib创建的,所以它的所有输出都是零,因此当您试图在
hideCustomizer
中调用其
webView
上的
animator
方法时,它会崩溃,因为它是零

相反,请在
self
上调用
urlditchange
(实际上是一个弱化的
self
,这样您就不会创建保留周期):

customizerURLObserver=customizerWebView.observe(\.url,选项:.new){[weak self]webView,在
let url=“\(字符串(描述:change.newValue))”
self?.urldichange(urlString:url)
}

现在我觉得自己很愚蠢。非常感谢您提供正确的代码和解释!现在我知道以后不要再犯同样的错误了。如果你有时间,请快速跟进:为什么在这样的情况下选择一个
弱自我
?在编写新项目或功能时,我如何知道何时选择一个
弱自我
?没问题!在这个特殊的例子中,我知道使用
[weak self]
,因为
self
拥有对
customizerURLObserver
的强引用,它拥有对
observe(uuu:options:)
调用中指定的变更处理程序闭包的强引用,如果我没有使
self
变弱的话,它将拥有一个对
self
的强引用–因此会有一个从self->customizerURLObserver->closure->self开始的保留周期,这将导致内存泄漏,因为这些东西都不会被释放。不过,一般来说,你几乎只需要知道什么是对什么的有力引用。