NSButton doesn't work anymore

Hi


I update xcode to version 11.3 and my OS to Mojave (10.14.6)

I had a macos app with NSButtons binded to a NSViewController


@IBAction func Tester(_ sender: NSButton) {

Swift.print("test activé")

}


(I made it very simple to isolate my problem)

the function Tester of my viewController is never called and I can't find why

Accepted Reply

OK, the reason is in fact :


In the appDelegate, when you call the menu tester:

    @IBAction func Tester(_ sender: Any) {
        testerWindow().showWindow(self)
    }


You create an instance of testerWindow and display a window object on screen.


But, when leaving Tester(), this instance is removed (it is not stored anywhere, it is only local to the IBAction).


However, windows stays on screen with its buttons (this is what is misleading but normal behavior), but the buttons target are now pointing to nil: they have no target to send the message for action anymore.


That is why it works by creating a global var in which to store the WindowController that is created when calling the menu, as per my previous post Dec 14, 2019 10:44 AM.

Replies

Is it a new project or an existing one ?


Things to check, in that order, if first are not enough:

- are the connections OK between IB an IBAction ?

- do a option - clean build folder

- restart the Mac. That may help complete XCode initialization.


I'm upgrading one machine to 11.3 and will test.

Just installed 11.3 (Version 11.3 (11C29)).

Mojave 10.14.6

Created a new app for OSX.


Have this simple code for NSViewController


import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    @IBAction func tester(_ sender: NSButton) {
        print("Le test marche avec 11.3")
    }
  
}


No surprise, it works:

Le test marche avec 11.3



Tested with an existing project: works as well.

My problem is still present

I precise that it is an existing project


when I run it, I have the following warnings;

2019-12-13 14:06:48.087149+0100 adminSQL[5941:111502] Metal API Validation Enabled

2019-12-13 14:06:48.114296+0100 adminSQL[5941:111963] flock failed to lock maps file: errno = 35

2019-12-13 14:06:48.114753+0100 adminSQL[5941:111963] flock failed to lock maps file: errno = 35


Also, my controller is not a NSViewController, but an NSWindowController


import Cocoa

class test: NSWindowController {
   
    override open var windowNibName: NSNib.Name? {
        let els = className.components(separatedBy: ".")
        if els.count > 1 {
            return els[1]
        } else {
            return els[0]
        }
    }
   
    override func windowDidLoad() {
        super.windowDidLoad()

        // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
    }
    @IBAction func Tester(_ sender: NSButton) {
        Swift.print("test activé")
    }
   
}

I reply to myself: ignore the second and third warnings, it was because I had an other instance of my App running

Some of your messages have been hidden.


Have you solved the issue ?

No my problem is still present

I said that I don't user an NSViewController, but an NSWindowController

you: I said that I don't user an NSViewController, but an NSWindowController


So what did you mean in the original post :

you: I had a macos app with NSButtons binded to a NSViewController


When you create a new App, you get a WindowController in IB as well as its ViewController.

Where do you add the button ? It is only possible in ViewController.


You also get a ViewController.swift file, which is what I copied in a previous answer.

What is the class in which you set the IBAction ?


To continue, could you either:

- post the code of all the controllers you have

- send an email so that we can share files.

I mean that in my nsviewcontroller the button’s action is never called This is for all kind of buttons: If I make a toolbar for my window and bind a button of the toolbar to a IBACTION function, the button is always disabled

Sorry, it is less and less clear.


in my nsviewcontroller the button’s action is never called

So, you define in NSViewController or in a Window Controller ?


If you cannot post email so that wa can share files, could you describe precisely:


- Where you create the NSButton in IB ?

- How do you connect to an IBAction ? In which exact file ?

- When you control-click on the button, what do you see in the inspector window ?

Sorry, I made a mistake in my previous post

it is truly a NSWindowController


first the code:

/  test.swift
//  adminSQL
//
//  Created by Patrice Rapaport on 13/12/2019.
//  Copyright © 2019 Patrice Rapaport. All rights reserved.
//

import Cocoa

class test: NSWindowController {
   
   
    override open var windowNibName: NSNib.Name? {
        let els = className.components(separatedBy: ".")
        if els.count > 1 {
            return els[1]
        } else {
            return els[0]
        }
    }
   
    override func windowDidLoad() {
        super.windowDidLoad()
       
      
   
    }
    @IBAction func Tester(_ sender: Any) {
        Swift.print("test activé")
    }
 
   
}


the name of my Swift file is test.swift and the name of the xib file is test.xib

the Class of File Owner in the IB interface is test

The delegate of the window is File's Owner

In the xib file, I add a NSButton, I maintain CTRL down and I link it to the func "Tester"

when I CTRL-Click the button in the B Interface, I see: action ... File Owner Tester:


I made a github (I'm not an expert at this). adminSQL is a complete App, but in aPPDelegate I wrote:


func applicationDidFinishLaunching(_ aNotification: Notification) {
test().showWindow(self)
return;


so it ony access test file.

The link to the git directory is :


https://github.com/patricerapaport/adminSQL

You did not answer those questions or suggestions either:


Is it a new project or an existing one ?


Things to check, in that order, if first are not enough:

- are the connections OK between IB an IBAction ?

- do a option - clean build folder

- restart the Mac. That may help complete XCode initialization.

Yes the connection etween IB and Action are OK (when I command click the Buton in IB, I see theAction

Yes I have clean the build forlder

and Yes, I restarted the mac

Yes the connection etween IB and Action are OK (when I command click the Buton in IB, I see theAction


You could see the action but the connection could be corrupted. You should remove the connection and recreate it.

But from what you said, that seems unlikely.


As there cannot be such a major bug that forbids buttons to work, that means the problem is elsewhere in code.

So either you show more or you give an address for contact or it is impossible to help further.

If you mean my Email adress, it is patrice @ rapaport.fr

Or do you mean something else?


To test, I've made a new project from scratch: h ttps: //github.com/patricerapaport/TestPushButton

it calls a NSViewController and when I click the push button, the action is performed

Now there is a menu "actions" with two submenus: "Tester" and "Cliquer"


The submenu "Tester" calls a NSWindowController and when I click the push button, nothing occurs

The submenu "Cliquer" calls also a NSWindowController but the button is subclasse as CButton

here the code:

import Cocoa

@IBDesignable class CButton: NSButton {
    var _controller: NSWindowController!
    var _target: Selector!
    @IBInspectable var controller: NSWindowController? {
        get {
            return _controller
        }
        set {
            _controller = newValue
        }
    }
    @IBInspectable override var target: AnyObject? {
        get { return _target as AnyObject?}
        set { _target = newValue as? Selector }
    }
   
    override func mouseDown(with event: NSEvent) {
        if action != nil {
            self.controller?.perform(self.target as? Selector, with: self)
        }
    }
}

class cliquerWindow: NSWindowController {

    @IBOutlet weak var btCliquer: CButton!
    override open var windowNibName: NSNib.Name? {
        let els = className.components(separatedBy: ".")
        if els.count > 1 {
            return els[1]
        } else {
            return els[0]
        }
    }

    override func windowDidLoad() {
        super.windowDidLoad()
        btCliquer.controller = self
        btCliquer.target = #selector(cliquer(_:)) as AnyObject
    }
   
    @IBAction @objc func cliquer(_ sender: Any) {
        Swift.print("CButton cicked")
    }
}


this work's.

I made the code of my NSWindowController simplier:


import Cocoa

@IBDesignable class CButton: NSButton {
    var _controller: NSWindowController!
    @IBInspectable var controller: NSWindowController? {
        get {
            return _controller
        }
        set {
            _controller = newValue
        }
    }
  
    override func mouseDown(with event: NSEvent) {
        if action != nil {
            self.window?.windowController?.perform(self.action, with: self)
        } else {
            super.mouseDown(with: event)
        }
    }
}

class cliquerWindow: NSWindowController {
    var num: Int = 1
    @IBOutlet weak var btCliquer: CButton!
    override open var windowNibName: NSNib.Name? {
        let els = className.components(separatedBy: ".")
        if els.count > 1 {
            return els[1]
        } else {
            return els[0]
        }
    }

    override func windowDidLoad() {
        super.windowDidLoad()
        btCliquer.controller = self
    }
  
    @IBAction @objc func cliquer(_ sender: Any) {
        Swift.print("CButton clicked \(num)")
        num += 1
    }
}


it work's well but as you can see, the var controller of the class CButton doesn't do anything

try to comment the line #37 of this code, and it will not work

https://github.com/patricerapaport/TestPushbuttonSimplified