I have created a 'BaseViewController' in a Xamarin.iOS library/csproj assembly (namespace: ios_common_lib).
This 'BaseViewController' is inherited by a class named 'LoginViewController' that lives in another assembly, my main Xamarin.iOS user-facing client/csproj assembly (namespace: experiments.ios).
On the iOS emulator/iOS 8.4, everything works fine as I expect, but when I run on my iPhone 5s device/iOS 8.4, the app crashes at the point where the 'Controller' would have been rendered on the screen.
After a THOROUGH and PAINFUL investigation, I narrowed down the problem to be due to differences in the namespaces of the 'base' and 'derived' controllers. Aarggh If I make the namespaces of both my 'BaseViewController' and the derived 'Controller' to the same namespace, it works on both device and emulator.
Now, I could have just shut up, and fixed my issue by changing my namespaces, but hey, what benefit is that to anybody ? and besides i really dislike when technology tools don't work consistently, and additionally, I'd hate to change my namespaces just to fix a symptom.
So, is there anybody out there that understands what is really going on, or is this a bug? I guess it's a bug, it has to be a bug, so then should we post this on Bugzilla ?
Here is the stack trace from the exception.
**System.NullReferenceException: Object reference not set to an instance of an object
at ObjCRuntime.Runtime.FindMethod (IntPtr typeptr, IntPtr methodptr, Int32 paramCount, System.IntPtr* paramptr) [0x0005e] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/ObjCRuntime/Runtime.cs:566
at ObjCRuntime.Runtime.GetMethodDirect (IntPtr typeptr, IntPtr methodptr, Int32 paramCount, System.IntPtr* paramptr) [0x00000] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/ObjCRuntime/Runtime.cs:329
at ObjCRuntime.Runtime.get_method_direct (IntPtr typeptr, IntPtr methodptr, Int32 paramCount, System.IntPtr* paramptr) [0x00000] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/runtime/Delegates.generated.cs:178
at at (wrapper native-to-managed) ObjCRuntime.Runtime:get_method_direct (intptr,intptr,int,intptr*)
at at (wrapper managed-to-native) ObjCRuntime.Messaging:void_objc_msgSend_IntPtr (intptr,intptr,intptr)
at UIKit.UIWindow.set_RootViewController (UIKit.UIViewController value) [0x00010] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/build/ios/native/UIKit/UIWindow.g.cs:327
at common_lib.UIWindowExtensions.SwitchRootViewController (UIKit.UIWindow window, UIKit.UIViewController controller, Boolean animated) [0x00014] in /Users/davidolubajo/Development-Local/XamarinStudioProjects/Walkr/common_lib/Extensions/UIWindowExtensions.cs:28
at experiments.ios.AppDelegate+c__AnonStorey1+c__async0.MoveNext () [0x000c4] in /Users/davidolubajo/Development-Local/XamarinStudioProjects/Walkr/experiments.ios/AppDelegate.cs:41
at --- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Users/builder/data/lanes/1962/8b265d64/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.m__0 (System.Object state) [0x00000] in /Users/builder/data/lanes/1962/8b265d64/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1006
at UIKit.UIKitSynchronizationContext+c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/UIKit/UIKitSynchronizationContext.cs:24
at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/Foundation/NSAction.cs:164
at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/UIKit/UIApplication.cs:63
at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0001c] in /Users/builder/data/lanes/1962/8b265d64/source/maccore/src/UIKit/UIApplication.cs:46
at experiments.ios.Application.Main (System.String[] args) [0x00008] in /Users/davidolubajo/Development-Local/XamarinStudioProjects/Walkr/experiments.ios/Main.cs:17
**
This issue comes down to a difference in GC behavior. You need the window to stay in memory, and the class property or field is how you keep it in memory. I'm not sure where the virtual property comes from. It should work just as well to just assign it to a private field, but maybe you have a base class that does something useful with the window.
I'm glad you like my blog! I have been pretty busy lately, but I'll get around to that third part eventually.
Answers
We definitely do this in our code, and it works for us. There must be something different that you're doing. Could you narrow it down to a small test case and attach a zip of that project here so I can look at it?
Hi @adamkemp ,
Big fan of your blog here..
i've learned so much on iOS and android from just a few of your blog posts. I can't wait for your next post on 'taming the android activity'. Thanks for all your effort and contribution.
So, enough of that and back to business...
I've actually narrowed down the issue to the right problem. It was because in my 'AppDelegate' 'DidFinishedLaunching', I was instantiating my window to a variable local to that method; not to the virtual 'Window' property that the AppDelegate naturally provides. See below...
Very very subtle, for the mere fact that it worked on the emulator, but not on the device.
TBH, i've had a number of scenarios that work on the emulator but not on the device.
It would be really nice if the two environments worked consistently....
This issue comes down to a difference in GC behavior. You need the window to stay in memory, and the class property or field is how you keep it in memory. I'm not sure where the virtual property comes from. It should work just as well to just assign it to a private field, but maybe you have a base class that does something useful with the window.
I'm glad you like my blog! I have been pretty busy lately, but I'll get around to that third part eventually.