I want to create an app where the NSWindow's title reflects the WKWebView's page title value. However, I've been having trouble with setting the window's title outside of initializer methods such as viewDidLoad, viewWillAppear, etc. Here's what I have thus far:
ViewController.swift
import Cocoa
import WebKit
class ViewController: NSViewController, WKUIDelegate, WKNavigationDelegate, NSWindowDelegate {
@IBOutlet var webView: WKWebView!
var webViewTitleObserver: NSKeyValueObservation?
let windowController: WindowController = WindowController()
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
webView.uiDelegate = self
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
preferences.javaScriptCanOpenWindowsAutomatically = true
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
webView.load("https://google.com")
// WebView Title Observer
webViewTitleObserver = self.observe(\.webView.title, options: .new) { webView, change in
let title = "\(String(describing: change.newValue))"
ViewController().titleChange(pageTitle: title)
}
}
override func viewWillAppear() {
self.view.window?.delegate = self
}
func titleChange(pageTitle: String) {
//self.view.window?.delegate = self
print("Start Title:", pageTitle)
// Fix Optional URL String
var title = pageTitle.replacingOccurrences(of: "Optional", with: "")
let brackets: Set<Character> = ["(", ")"]
title.removeAll(where: { brackets.contains($0) })
print("Clean Title:", title)
self.view.window?.title = title
self.view.window?.update()
}
}
// MARK: Extensions
// WKWebView Extension
extension WKWebView {
func load(_ urlString: String) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
load(request)
}
}
}
This code currently prints to the console whenever the title is changed, so the page titles are coming through as such:
Start Title: Optional(Optional("Google"))
Clean Title: "Google"
However, the window's title refuses to change in the titleChange function. Why is this?
WindowController.swift (if needed)
import Cocoa
class WindowController: NSWindowController, NSWindowDelegate {
override func windowDidLoad() {
super.windowDidLoad()
window!.delegate = self
window!.titlebarAppearsTransparent = true
window!.isMovableByWindowBackground = true
}
}
What am I doing wrong?
You are creating a new view controller in your observer:
And call
titleChange()on it. So, because this is a new controller, it has no windows and has nothing to do with the currently presented view hierarchy.To fix it, update your observer to something like this:
I have changed the arguments and capture
weakreference for theselfand then call yourtitleChange()function on it. In this case,self.view.window?.title = titlewill be called on the controller you see on the screen.