locked
Weird problems assigning action to NSButton RRS feed

  • Question

  • User55350 posted

    Something really strange is plaguing part of a largish project I'm working on. I've got a custom NSView with controller in my MonoMac project, and in IB creat actions for various NSButtons in the view. The partial methods are placed in the .designer.cs file, and I implemented them.

    But…. they never get called when clicking the button. In fact, even worse, when clicking the buttons, one of two things happens: a) Nothing at all b) Hard crash in native code

    The super annoying part about this is that sometimes, nothing happens. I open the xib, DO NOTHING, close it, and rebuild all. Then, BOOM! (as attached). In the attached, 'Biff' is the brand new NSView with controller with a single button on it. In fact, I didn't even click a button in that view to produce this crash.

    The NSView in this case is part of my application's preferences dialog. Other pages in the prefs dialog work perfectly fine, including those with actions assigned via IB in Xcode.

    I deleted all the buttons, all the actions, etc, and recreated and no dice - same problem. In fact, I created an entirely new NSView with a single button on it (Biff) and same story. Either nothing happens at all, or crash in native code.

    This also happens if I hook up an event handler in code and don't use IB to create the action.

    At this point, I'm now afraid to edit or create any new existing or create new UI elements.

    A bit more background about the app - it's rather large, and I'm in the process of open sourcing it in git, but as of yet, the code's still not easily available…

    The project is created using MonoMac, and consists of five assemblies and the application itself. The preferences dialog discovers the preference pages and creates them via MEF.

    All of this was working perfectly a few weeks ago. The only changes I can recall pertaining to this recently were a commenting pass, code cleanup (deleting commented out code), and setting the IB and Xcode versions in Xcode. So the perplexing thing here is what the heck changed.

    But, as I said, I created a brand new NSView with controller and exactly the same thing happens. (It is also instantiated via MEF when the prefs dialog is loaded).

    Some other info: Mac OS X 10.8.5 Xamarin Studio: 5.8.3 Xcode 4.6.1 (with certain plugins removed -- Thanks, iTunes! :P MonoMac, not Xamarin.Mac (have to do a lot if p/Invokes for IOKit and some other issues found along the way.)

    Tuesday, December 22, 2015 12:11 AM

All replies

  • User35201 posted

    So, as you may expect, my first suggestion is to try porting your application to Xamarin.Mac Unified. We've made quiet a few improvements and bug fixes, and this might already be fixed. :)

    Beyond that, taking a look at your crash, starting with the second log (nativecrash_...) it looks like the following is happens:

    • We're in menu code, invoking something that runs a model loop, which is then handling a mouse down event, we're trying to invoke the action, and while sending it we explode with a BAD_ACCESS.
    • This very often means that the thing that you are invoking got garbage collected underneath you.
    • We fixed a large number of issues in this class over the years, and in particular with new-ref-count (https://developer.xamarin.com/guides/ios/advanced_topics/newrefcount/).

    If my wild guess is correct, then here's a few suggestions to nail it down:

    • Run this chunk of code early after your application GUI spins up:
     new System.Threading.Thread (() => 
        {
            while (true) {
                System.Threading.Thread.Sleep (1000);
                GC.Collect ();
            }
        }).Start ();  
    
    • This will, every second, run the garbage collector, so if some object isn't "nailed down" correctly, it should show up consistently, as opposed to completely "randomly" from your perspective.
    • Make a static HashMap and shove everything related to this crash inside of it. This will force GC roots, and prevent things from being collected.

    Obviously a test case would make diagnosing this a lot easier, but that's something to start with. :)

    Let me know if any of that works, or is ineffective.

    Tuesday, December 22, 2015 5:01 AM
  • User55350 posted

    Thanks! Debug builds of my app do have a command to run a on-shot GC.Collect(), but I haven't put in something to keep pressure on it like that. ;)

    Unfortunately, for some reasons we may have covered in a PM, a move to Xamarin.Mac isn't in the cards at this time.

    Your analysis is pretty much on point… The preferences dialog is invoked using the menu, and it's a dialog. In the dialog, there is a button, and when clicked, it's supposed to call back.

    Ironically, in some code that I thought I'd disabled long, long, ago, my framework used to keep a 'coupling' between the view and the controller. It didn't seem necessary, so I got rid of it -- though my project notes still have a TODO about … drum roll please … checking to see if I need to keep an explicit reference to controllers.

    I'm going to add that excellent 'GC pressure loop' to the debug toolbox for my app, and get back to you. Hopefully the open-sourcing of my project will help open the door to moving to Xamarin.Mac, though I fear making that move might turn into a lot of work, too! :open_mouth:

    Tuesday, December 22, 2015 3:29 PM
  • User55350 posted

    You nailed it! Sure enough - finalizer was being called on my controllers. In fact, the settings dialog class even had the place to stash these guys, but wasn't using it. sigh That work must have fallen on the floor at some point in the past. Thanks a ton for the reminder!

    Wednesday, December 23, 2015 6:03 AM