Сбой NSAnimationContext при вызове наблюдателем - PullRequest
1 голос
/ 27 марта 2020

У меня есть два WebView: webView и customizerWebView. Оба из этих WKWebViews связаны конечным ограничением. По сути, когда я go в меню и нажимаю «Показать настройщик» showCustomizer() или «Скрыть настройщик» hideCustomizer(), он вызывает соответствующую функцию и либо показывает, либо скрывает все вещи, связанные с customizerWebView.

Чтобы уточнить, все работает и анимируется, как и ожидалось, при вызове этих функций из подключенных NSMenuItems. Однако , когда show/hideCustomizer() вызывается из Обозревателя, который по существу обнаруживает URL - ie. url.contains("#close") - приложение вылетает в первой строке animator() кода с ошибкой: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

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
        })
    }
}

Может кто-нибудь пожалуйста просветите меня, почему эта анимация выглядит и работает безупречно 100 раз при вызове из NSMenu, но вылетает, когда hideCustomizer() вызывается один раз из функции Observer?

Я также пытался вызвать объектную функцию NSMenu hideCustomizerMenu(self), но безрезультатно.

1 Ответ

1 голос
/ 27 марта 2020

В строке:

ViewController().urlDidChange(urlString: url)

вы по ошибке создаете новый экземпляр вашего класса контроллера представления и вызываете urlDidChange для этого экземпляра. Поскольку этот новый экземпляр не создается из раскадровки / xib, все его выходы равны нулю, и, таким образом, когда вы пытаетесь вызвать метод animator для его webView в hideCustomizer, происходит сбой, потому что он равен нулю.

Вместо этого вызовите urlDidChange на self (на самом деле ослабленный self, чтобы не создавать цикл сохранения):

customizerURLObserver = customizerWebView.observe(\.url, options: .new) { [weak self] webView, change in
    let url = "\(String(describing: change.newValue))"
    self?.urlDidChange(urlString: url)
}
...