Search code examples
c#cocoamonomac

"unrecognized selector" on Monomac while creating UI elements programmatically


I am trying to create a basic RPN calculator on C#. Currently I am developing it using Monomac, as a Mac app, but I wanted to make it easier to port and develop for several platforms (I'm thinking about Android). For that purpose, rather than making all the buttons in Interface Builder, I am making everything(except the enter button, the field where the numbers are typed, and the area where the stack is shown) programmatically.

To achieve this, I made a class called AgnosticLayout. You can create AgnosticLayouts either with the Button function, which creates a single button that executes an action, or the Horizontally and Vertically functions, which group AgnosticLayouts together. The important method of this class is Display<T>, which, given a way to turn single operations into Ts, and a way to group Ts together, returns a complete layout of type T: so that I can describe my buttons as an AgnosticLayout, and each platform is able to turn it into its own kind of GUI(in the case of Mac, into an NSView).

I already was able to implement the function that turns operations into buttons, and was able to show one, but I'm struggling with joining buttons.

My current function is:

NSView Joiner(IEnumerable<NSView> elems, bool isLeftRight)
{
    NSView view = new NSView();
    int i = 0; // used to give a unique key to each element
    string[] keys = new string[elems.Count()];
    NSView[] elemarray = new NSView[elems.Count()]; // array of elements to be fed to NSDictionary for the constraint
    string visualformat;
    if (isLeftRight) // Creating the visual format string
    {
        visualformat = "|-0-";
    }
    else
    {
        visualformat = "V:|-0-";
    }
    foreach (NSView elem in elems)
    {
        char a = (char) (i+97);
        keys[i] = a.ToString();
        elemarray[i] = elem;
        i += 1;
        view.AddSubview(elem);
        visualformat += "[" + a.ToString() + "]-0-"; 
    }
    visualformat += "|";
    NSDictionary elemsdict = NSDictionary.FromObjectsAndKeys(keys,elemarray);
    view.AddConstraints (NSLayoutConstraint.FromVisualFormat (
        visualformat,
        NSLayoutFormatOptions.None,
        new NSDictionary (),
        elemsdict)
    );

This is not only ugly as fuck, but also doesn't work. I get this when I run everything:

2013-11-10 14:00:14.971 CalculatorMac[2006:1007] -[NSButton copyWithZone:]: unrecognized selector sent to instance 0x6555bc0
2013-11-10 14:00:14.972 CalculatorMac[2006:1007] -[NSButton copyWithZone:]: unrecognized selector sent to instance 0x6555bc0

I suppose this is an ObjC exception rather than a C# one, which means that Cocoa is crashing, not the program itself. I don't know what the message means.

I haven't found any useful solution in Google, mainly because most of them are for ObjC, a language I do not understand.

Relevant files:

MainWindowController.

Calculator: two important classes live here, Calculator(receives orders and keeps the stack) and AgnosticLayout.

The buttons being displayed are those in Calculator.AgnosticLayout.DefaultLayout().

I know that the way to make unique names on Joiner is ugly: I don't care about that yet, and I think it's working right atm, because if don't use any constraints at all the whole still fails.

Also, I come from playing in Haskell for a lot of time, and I don't have a lot of experience with OO, so if there is a more idiomatic way to do what I want to do, I'm all ears.


Solution

  • I am not sure that I see anything(not that I would know in this gibberish language;) ) but your error is coming from copying an NSButton, which doesn't adopt NSCopying...

    this could happen if you are copying a button or using it as a key in a dictionary which implicitly retains it's objects and copies it's keys.

    EDIT

    your parameters are backwards here:

    NSDictionary.FromObjectsAndKeys(keys,elemarray); should be ->
    NSDictionary.FromObjectsAndKeys(elemarray,keys);

    so you are actually using the buttons as keys.