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

Answered by Claude31 in 398401022

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.

You said: ' the button’s action is never called'


How do you know ?

Is it because you do not see the log ?

Have you check that the right pane of the console is open ? (there are 2 small buttons at the bottom right, for displaying left and right part of console ; check that the right is selected (should appear blue).

Yes of course I see the log, I see it, and I dont see the print action

and also I put a breakpoint on the Swift.Print contained in IBAction

OK.


C'était ma dernière piste si je ne peux pas inspecter l'ensemble du projet.

Mais je vous ai envoyé les githubs contenant les projets dans leur ensemble! et je vous ai mis également mon adfresse mail, comme vous le demandiez

Ces messages sont marqués beeing moderated

Les messages sont moderated à cause des url !


Il faut écrire par ex

h ttps avec un blanc

ou moi @ some . com aussi avec des blancs.

Je ne suis pas certain que vous allez voir les messages qui étaient en train d'etre modérés, mais j'ai développé un petit projet partant de rien que vous pouvez trouver sur github: github/patricerapaport/TestPushbuton


La première vue- est une NSViewController (dans le Main.Storyboard) et le bouton qu'elle contient fonctionne correctement

La seconde vue, TesterWindow, que vous pouvez accéder avec le menu Actions/Tester est une NSWindowController, et le bouton ne déclenche pas l'action à laquelle il est relié

La troisième vue, CliquerWindow, que vous pouvez accéder avec le menu Actions/cliquer est également une NSWindowController dans laquelle j'ai subclassé le bouton pour le faire réagir à MouseDown. Cela fonctionne correctement et en voici le code:


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


Vous remarquerez que la variable controller de CButton n'est pâs utilisée. Donc on devrait pouvoir commenter la ligne 37. Siu vous le faites, le bouton ne réagira plus au click.

Problem is in the IBAction


    @IBAction func tester(_ sender: Any) {
        TesterWindow?.showWindow(self)
    }


You create a new instance of the TesterWindow when you hit the button.


You should:

- create a global var for the controller:

var testerWindowController : TesterWindow?


- set it in finishLauncing

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
        testerWindowController = TesterWindow()
    }


-Then use it in IBAction

    @IBAction func tester(_ sender: Any) {
        testerWindowController?.showWindow(self)
    }

Sorry to bother youo with this, but the main ViewController was there only to demonstrate that in a NSViewController the IBAction is called


This is not the case for an NSWindowController, as demonstrated in TesterWindow


I have a solution in the controller CliquerWindow, but is it normal to have to subclass the NSButton to make it fuctionnal?

Accepted Answer

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.

NSButton doesn't work anymore
 
 
Q