I'm trying to understand how to change data in a variable (var or a label) in between two different views or functions.
I'm migrating from swiftUi, I was used to create stateobject and accessing the variable through environment variables throughout the app. But now the cocoa framework confuses me a bit.
So I created two views CustomView1 and CustomView2, one of them contains a button and other contains a label. So, when the button clicks, the label's string value should change.
But the issue is nothing shows up when run. Not even the window show up.
Error: No errors
main.swift
import Cocoa
let app = NSApplication.shared
let appDelegate = App2()
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps:true)
app.run()
App2.swift
import Cocoa
class App2: NSObject, NSApplicationDelegate {
var window:NSWindow!
var view: NSView!
var customView1: CustomView1!
var customView2: CustomView2!
func buildMenu() {
let mainMenu = NSMenu()
NSApp.mainMenu = mainMenu
// **** App menu **** //
let appMenuItem = NSMenuItem()
mainMenu.addItem(appMenuItem)
let appMenu = NSMenu()
appMenuItem.submenu = appMenu
appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q")
}
func buildWnd() {
let _wndW: CGFloat = 400
let _wndH: CGFloat = 400
//@State var title: String = "app title"
let appTitle: String = "app title"
window = NSWindow(contentRect: NSMakeRect(0, 0, _wndW, _wndH), styleMask: [.titled, .closable, .miniaturizable, .resizable], backing: .buffered, defer: false)
window.center()
window.title = appTitle
window.makeKeyAndOrderFront(window)
// Create a label
let labelFrame = NSRect(x: 50, y: 50, width: 200, height: 30)
let labelText = "Hello, Cocoa!"
customView1 = CustomView1(frame: NSRect(x: 10, y: 50, width: 120, height: 50))
customView2 = CustomView2(frame: NSRect(x: 10, y: 100, width: 120, height: 50))
window.contentView?.addSubview(customView1)
window.contentView?.addSubview(customView2)
}
class CustomView1: NSView {
let customView2 = CustomView2(frame: NSRect(x: 10, y: 50, width: 100, height: 30))
func createButton(frame: NSRect, title: String) -> NSButton {
let button = NSButton(frame: frame)
button.title = title
button.bezelStyle = .rounded
button.target = self
button.action = #selector(buttonClicked(_:))
return button
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
let button = createButton(frame: NSRect(x: 10, y: 10, width: 100, height: 30), title: "Click me!")
self.addSubview(button)
self.addSubview(customView2)
}
@objc func buttonClicked(_ sender: NSButton) {
customView2.label.stringValue = "Button clicked!"
}
}
class CustomView2: NSView {
let label = NSTextField(frame: NSRect(x: 10, y: 10, width: 100, height: 20))
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
label.stringValue = "Hello, world!"
label.isEditable = false
label.isSelectable = false
label.isBezeled = false
label.drawsBackground = false
self.addSubview(label)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
func applicationDidFinishLaunching(_ notification: Notification) {
buildMenu()
buildWnd()
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}
The following source code is a re-arrangement of your demo. The two custom views need to be separate from the appDelegate. Custom view2 is more correct than Custom view1 as far as adding controls. You will need to create a new file called 'main.swift' by using Xcode's File/New/File. Copy/paste the following code into that file in its entirety, then delete the pre-supplied AppDelegate and it should run without error.