Bug 29837 - Outlets are null in the IntPtr constructor
Summary: Outlets are null in the IntPtr constructor
Status: RESOLVED ANSWERED
Alias: None
Product: iOS
Classification: Xamarin
Component: General ()
Version: XI 8.10
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2015-05-07 09:59 UTC by John Miller [MSFT]
Modified: 2015-05-08 10:23 UTC (History)
6 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Test Case (13.97 KB, application/zip)
2015-05-07 09:59 UTC, John Miller [MSFT]
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description John Miller [MSFT] 2015-05-07 09:59:36 UTC
Created attachment 11118 [details]
Test Case

**Overview:**

   After updating to XS 5.9 and XI 8.10, Outlets are not initialized and are null when accessing them in the IntPtr constructor of the linked controller from a Storyboard.

**Steps to Reproduce:**

   1. Run the attached sample on iOS
   2. Press the Popup button

**Actual Results:**

   The app will crash because the Outlets being accessed in the PopupController are null. 

**Expected Results:**

   The outlets should not be null. 

**Build Date & Platform:**

   === Xamarin Studio ===

Version 5.9 (build 431)
Installation UUID: f085d92d-1281-4a1b-aac3-be3583d942ee
Runtime:
	Mono 4.0.0 ((detached/d136b79)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 400000143

=== Apple Developer Tools ===

Xcode 6.1.1 (6611)
Build 6A2008a

=== Xamarin.iOS ===

Version: 8.10.0.267 (Indie Edition)
Hash: 6481535
Branch: master
Build date: 2015-04-27 04:38:13-0400

=== Xamarin.Android ===

Version: 5.1.0.115 (Starter Edition)
Android SDK: /Users/admin/Library/Developer/Xamarin/android-sdk-mac_x86
	Supported Android versions:
		2.3   (API level 10)
		4.0.3 (API level 15)
Java SDK: /usr
No Java runtime present, requesting install.

=== Xamarin Android Player ===

Not Installed

=== Xamarin.Mac ===

Not Installed

=== Build Information ===

Release ID: 509000431
Git revision: 7560726734fc7267de2fa9abed2509968deefaa8
Build date: 2015-04-17 19:25:48-04
Xamarin addins: 2e772c734ab3148054eae7bf8949f340fdeb5e5e

=== Operating System ===

Mac OS X 10.10.2

**Additional Information:**

   The outlets seem to be initialized once ViewDidLoad is called, however that is different than previous versions. If this is intended, please explain why it changed.
Comment 1 John Miller [MSFT] 2015-05-07 10:01:16 UTC
Additionally, if the View.Frame is changed in the constructor, then Outlets will also be null in the ViewDidLoad method. 

To confirm that, change the constructor in the test project to:

public PopupController (IntPtr handle) : base (handle)
{
this.View.Frame = new CoreGraphics.CGRect (0, 0, 300, 450);
}

Now try and access any Outlet in ViewDidLoad and it will be null.
Comment 2 Alan McGovern 2015-05-07 10:04:15 UTC
This is unrelated to the designer as the issue is at runtime in the simulator/on device.
Comment 3 Alan McGovern 2015-05-07 10:09:15 UTC
However I do think you've done it wrong.

From the iOS Docs of 'viewDidLoad':
This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/#//apple_ref/occ/instm/UIViewController/viewDidLoad

I'm pretty sure that if you rely on outlets being set in the constructor you are going to break. Apple only guarantee that the outlets will be set when viewDidLoad is invoked.
Comment 4 Sebastien Pouliot 2015-05-07 10:18:33 UTC
There’s a lot of things people should *not* do in the .ctor - that’s might break whenever Apple change it's behaviour.

Figure 4-1 of https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

Still this looks like a duplicate of #29803, something changed in the initialization order.
Comment 5 Sebastien Pouliot 2015-05-08 10:23:21 UTC
It does work correctly when following the previously mentioned Apple guidelines/documentation. Change to:

		public PopupController (IntPtr handle) : base (handle)
		{
		}

		public override void ViewDidLoad ()
		{
			base.ViewDidLoad ();
			// this label outlet use to be valid when loading from a handle
			this.lblInfo.Text = "Xamarin Case 156222";
		}

and have it shown somehow, e.g.

		partial void btnPopup_TouchUpInside (UIButton sender)
		{
			// this causes the constructor to be called, which then causes the crash
			PopupController controller = (PopupController)Storyboard.InstantiateViewController("PopupController");
			this.ShowViewController (controller, null);
		}

and you have connected/non-null outlets.

note: unrelated with #29803