Forum Xamarin Xamarin.iOS

Constructor not called in UIView derived class (storyboard custom class)

GrigoryBurdenkoGrigoryBurdenko RUMember
edited May 2013 in Xamarin.iOS

I create new Singleview Storyboard application. In xcode I add UIButton to view and change custom class property to DerivedUIButton. After class generation I write next code in DerivedUIButton class:

    public partial class DerivedUIButton : UIButton
      {
          public DerivedUIButton (IntPtr handle) : base (handle)
          {
              this.TouchDown += ((sender, e) => {
                  var alert = new UIAlertView ("test", "test", null, "ok", null);
                  alert.Show ();
              });
          }
    }

I run application in debug mode and I see that constructor not called and alert not showed after touch.
But if I add this redundant code:

public override void Draw (System.Drawing.RectangleF rect)
{
  base.Draw (rect);
}

Constructor is called and alert shows.

A similar behavior is observed in other custom classes for uicontrols.

It's bug or I doing something wrong?

About Xamarin studio:

Xamarin Studio
Version 4.0.5 (build 4)
Runtime:
Mono 3.0.10 ((no/eff4cb5)
GTK 2.24.18
GTK# (2.12.0.0)
Package version: 300100000

Apple Developer Tools
Xcode 4.6.1 (2067)
Build 4H512

Xamarin.iOS
Version: 6.3.4.36 (Business Edition)
Hash: 9eb42f8
Branch:
Build date: 2013-11-04 10:49:08-0400

Posts

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I've seen similar behavior in Xamarin.Android. Specifically, if you use a custom Application subclass then the constructor is not called unless you also override OnCreate (or possibly any other override). It seems like the Xamarin framework thinks that if you don't have any overrides then there isn't any reason to construct the managed object, but sometimes you just want the constructor to be called.

  • JamesLaveryJamesLavery GBBeta, University ✭✭✭✭✭

    I've had the same problem - @adamkemp's solution worked for me. Overriding something triggers the class to be created.

  • MichaelBluesteinMichaelBluestein USInsider, University, Developer Group Leader ✭✭✭

    When the object is deserialized from a nib or storyboard, it is sent initWithCoder:, which you can bind from C# like this:

    public partial class DerivedUIButton : UIButton
    {   
        [Export("initWithCoder:")]
        public DerivedUIButton (NSCoder coder) : base(coder)
        {
            this.TouchDown += ((sender, e) => {
                var alert = new UIAlertView ("test", "test", null, "ok", null);
                alert.Show ();
            });
        }
    }
    
  • JamesLaveryJamesLavery GBBeta, University ✭✭✭✭✭

    Mike,
    Thanks - this works. Putting that attribute causes my class to be constructed without other overrides.

    However, for custom TableViewController:

    public partial class AppointmentListViewController : UITableViewController
    {
    
        [Export("initWithCoder:")]
        public AppointmentListViewController(IntPtr handle) : base (handle)
        {
    
            TableView.Source = new AppointmentSource(this);
        }
    }
    

    I now get an error:

    MonoTouch.Foundation.MonoTouchException: Objective-C exception thrown. Name: NSInvalidArgumentException Reason: -[UINibDecoder view]: unrecognized selector sent to instance 0xd25fa00

    Is this something you've come across?

    James

  • AlexCorradoAlexCorrado USXamarin Team Xamurai

    You shouldn't export the IntPtr constructor. Note that in @mikeb's example, the argument is NSCoder, not IntPtr; that's why you're seeing that exception.

    Instead of the initWithCoder approach, I'd recommend keeping the IntPtr constructor (but not exported!) and putting your logic in the AwakeFromNib method instead. The difference is explained at http://stackoverflow.com/a/492358/578190

Sign In or Register to comment.