This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.

Bug 1449

Summary: Outlet property cannot be set from xib that uses subclass
Product: iOS Reporter: Marco <mpiralli>
Component: GeneralAssignee: Bugzilla <bugzilla>
Status: RESOLVED FIXED    
Severity: major CC: andycted, bryan.moulton, chatton, dmacd10, mhutch, miguel, mono-bugs+monodevelop, mono-bugs+monotouch, rolf
Priority: Normal    
Version: 5.0   
Target Milestone: Untriaged   
Hardware: Macintosh   
OS: Mac OS   
Whiteboard:
Tags: Test Case URL:
External Submit: ---
Attachments: Example project
Exmple project ver 2

Description Marco 2011-10-12 09:24:14 EDT
Created attachment 680 [details]
Example project

I migrated my application from monodevelop 2.6 to 2.8 and from XCode 3 to XCode
4.
If I override a UIViewController the method ViewdidLoad doesn't raised more
from both the base view than from overrided view.
In the attached example: I created the BaseView; ProView is inherited from the
base view. 
The main class raised the "Object reference not set to an instance of an
object" exception when try to set the button's title on the baseView, but the
button exists.
Comment 1 Michael Hutchinson 2011-10-12 09:40:29 EDT
Did you intend for the ProView claa to load BaseView.xib? That's what your code
is doing. ProView.xib isn't used at all.
Comment 2 Marco 2011-10-12 09:48:02 EDT
Sorry, I missed to add to the sample the LoadNib command

this is the ProView Class corrected

namespace OverrideProject
{
    public partial class ProView : BaseView
    {
        //loads the ProView.xib file and connects it to this object
        public ProView () : base ()
        {
        }

        public override void ViewDidLoad ()
        {
            MonoTouch.Foundation.NSBundle.MainBundle.LoadNib ("ProView", this,
null);
            base.ViewDidLoad ();
            BtnSlave2.SetTitle ("Button 2 - From Pro View",
UIControlState.Normal);
        }

    }
}
Comment 3 Michael Hutchinson 2011-10-12 09:53:59 EDT
The base BaseView ctor is still passing the "BaseView" nib name to the
UIViewController ctor, so ProView is still loading two nibs. I don't know
exactly what sequence they're loaded, but it's possible you may not end up with
the one you expect.

I would suggest adding another ctor to BaseView:
protected BaseView (string nibName) : base (nibname, null)
{
}

Then ProView can load the correct nib from its ctor:
public ProView () : base ("ProView")
{
}
Comment 4 Marco 2011-10-12 10:23:32 EDT
I tried with your suggestion but I still have the same problem.

Attached the Example project updated.
Comment 5 Marco 2011-10-12 10:24:27 EDT
Created attachment 681 [details]
Exmple project ver 2
Comment 6 Marco 2011-10-13 08:14:06 EDT
Hi, any news about this issue?

Thanks
Comment 7 Michael Hutchinson 2011-10-18 06:21:56 EDT
The problem is that ProView and BaseView both define an outlet called BtnMain1.
When the xib is instantiated, the button is connected to the most derived one,
i.e. the one on ProView, so the one on BaseView is null.

However, even after solving this problem by removing the BtnMain1 from ProView,
I get the following error when loading the xib:

Unhandled Exception: System.Exception: Failed to find selector setBtnMain1: on
ProView
  at MonoTouch.ObjCRuntime.Runtime.GetMethod (IntPtr klass, IntPtr selptr)
[0x00022] in
/Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:141 
  at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime:GetMethod
(intptr,intptr)
  at (wrapper managed-to-native)
MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)

This looks to me like a problem with the MT obj-c bridge, so I'm reassigning.
Comment 8 Michael Hutchinson 2011-10-18 06:36:15 EDT
I tested a xib that does this, i.e. connects to outlets on the controller class
and controller's superclass, and it works in obj-c.
Comment 9 Marco 2011-10-18 06:55:18 EDT
Then, Can you confirm that it's a problem with MT?
Do you know if this issue will be solved in the next released? 
Now we have some solutions with this logic, and this problem is a blocker...

Thanks
Comment 10 Michael Hutchinson 2011-10-19 04:28:42 EDT
You might be able to work around it by making the base definition virtual, then
trivially overriding it in the subclass, e.g. in the base class do:

[Outlet]
protected virtual MonoTouch.UIKit.UIButton BtnMain1 { get; set; }

and in the subclass, do:

protected override MonoTouch.UIKit.UIButton BtnMain1 {
    get { return base.BtnMain1; }
    set { base.BtnMain1 = value; }
}


You should move these to the non-designer class parts to prevent the designer
from altering them.
Comment 11 Marco 2011-11-02 12:51:29 EDT
Hi, 
sorry for delay. I tried your workaround but in the "designer.cs" is not
possibile to use object (in the subclass) from the base class because the
objects are declared private. 
Moreover this workaround it's unusable because every time I change the xib from
IB the designer file is regenerated automatically.
Comment 12 Michael Hutchinson 2011-11-02 15:32:53 EDT
Please note my comment about moving the outlets to the non-designer class part
so that the designer does not alter them.
Comment 13 Marco 2011-11-09 11:34:31 EST
Hi,
the suggested workaround, even if it could work, it's unusable.
For every "standard" view I have to manually move and  modify outlets
definitions marking them as virtual in order to override them in the
subclasses.
Moreover everytime I'll add a new control to the standard view (or remove an
existing one) I'll have to manually update all subclasses.
This is not inheritance.
Any news about the task reassingning? Do you have an idea if this issue will be
resolved and which release will include the fix?
Thanks in advance!
Regards
Comment 14 Daniel 2011-12-24 19:04:00 EST
I've just tripped on the same issue. Any word on a resolution or a better
workaround?
Comment 15 Andy 2012-01-04 11:45:25 EST
Same here. The workaround 'works', but I suspect one could easily hit the
problem multiple times at random.

My solution in these cases is becoming, even more now, to move all the design
to code and ignore IB
Comment 16 Chris Hatton 2012-05-14 07:31:13 EDT
I would like to bump this issue.

This decision to make outlets private seriously cripples the usefulness of XIB
integration - with use of ViewController base class becoming impossible. These
outlets should be protected access in my opinion... 

Any word on whether these can be changed to protected, and if not, what is the
reason? Thanks.
Comment 17 Michael Hutchinson 2012-05-14 10:47:27 EDT
MD importing outlets as private doesn't make anything impossible. Why do you
say it does?
Comment 18 Miguel de Icaza 2013-02-11 22:14:12 EST
Someone was asking today on the mailing lists whether we should flag outlets as
"internal".

I do not have strong opinions on this, but I am adjusting the priorities.
Comment 19 Michael Hutchinson 2013-02-12 01:30:39 EST
This bug is not about the accessibility of outlets, it's about a bug in
MonoTouch's ObjC bridge.
Comment 20 Rolf Bjarne Kvinge 2013-03-14 19:46:09 EDT
The problem mentioned in comment 7 (Failed to find selector setBtnMain1: on
ProView) has been fixed (with the new registrar).

The original problem still exists though (the most derived outlet is used
always), but that doesn't look like a bug in MonoTouch (imho the generated code
should not duplicate outlets in the first place, but I might be wrong about
this).
Comment 21 Michael Hutchinson 2013-03-14 21:15:44 EDT
There is no "generated code" there is only "synced code". In the original code
the user had created a duplicate output, probably to work around the real issue
which I described in comment 7, so I think we can mark this as fixed.
Comment 22 Michael Hutchinson 2013-03-28 00:22:43 EDT
*** Bug 11455 has been marked as a duplicate of this bug. ***
Comment 23 Rolf Bjarne Kvinge 2013-07-15 18:57:43 EDT
The fix mentioned in comment #20 (the new registrar) is not enabled by default
(because in some cases the new registrar will error out on invalid code we
previously allowed, effectively breaking existing code).

To enable this fix add this to the additional mtouch arguments in the project's
iOS Build options:

--registrar:dynamic (for simulator builds)
--registrar:static (for device builds)
Comment 24 Rolf Bjarne Kvinge 2013-07-22 13:24:05 EDT
Note that the latest beta (6.3.8) is broken wrt comment 23, but it's be fixed
for the final 6.4 release.