baskren/Forms9Patch

NullReferenceException in DrawLabel on iOS

Opened this issue · 0 comments

Description

Returning to a Xamarin Shell page where a Forms9 label has been shown and then hidden seems to cause a NullReferenceException.

Steps to Reproduce

ShellContent firstPage;
ShellContent secondPage;
label.IsVisible = true;
await Task.Delay(100);
label.IsVisible = false;
await GoToAsync($"//{secondPage.Route}");
firstPage.IsVisible = false;
await Task.Delay(100);
firstPage.IsVisible = true;
await GoToAsync($"//{firstPage.Route}");

Expected Behavior

FirstPage is shown

Actual Behavior

System.NullReferenceException: Object reference not set to an instance of an object
  at Forms9Patch.iOS.LabelRenderer.DrawLabel (System.Double width, System.Double height) [0x0001e] in <2738c9ce95a3438fb36953f241f4498f>:0 
  at Forms9Patch.iOS.LabelRenderer.LayoutSubviews () [0x0001d] in <2738c9ce95a3438fb36953f241f4498f>:0 
  at (wrapper managed-to-native) ObjCRuntime.Messaging.void_objc_msgSend(intptr,intptr)
  at CoreAnimation.CALayer.LayoutSublayers () [0x00008] in /Library/Frameworks/Xamarin.iOS.framework/Versions/16.4.0.15/src/Xamarin.iOS/CoreAnimation/CALayer.g.cs:456 
  at Xamarin.Forms.Platform.iOS.VisualElementTracker+<>c__DisplayClass32_0.<OnUpdateNativeControl>g__update|0 () [0x0015d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementTracker.cs:277 
  at Xamarin.Forms.Platform.iOS.VisualElementTracker.OnUpdateNativeControl (CoreAnimation.CALayer caLayer) [0x002be] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementTracker.cs:361 
  at Xamarin.Forms.Platform.iOS.VisualElementTracker.UpdateNativeControl () [0x00060] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementTracker.cs:411 
  at Xamarin.Forms.Platform.iOS.VisualElementTracker.SetElement (Xamarin.Forms.VisualElement oldElement, Xamarin.Forms.VisualElement newElement) [0x00038] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementTracker.cs:387 
  at Xamarin.Forms.Platform.iOS.VisualElementTracker..ctor (Xamarin.Forms.Platform.iOS.IVisualElementRenderer renderer, System.Boolean trackFrame) [0x0006b] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementTracker.cs:56 
  at Xamarin.Forms.Platform.iOS.VisualElementTracker..ctor (Xamarin.Forms.Platform.iOS.IVisualElementRenderer renderer) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementTracker.cs:42 
  at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x000ef] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementRenderer.cs:276 
  at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementRenderer.cs:158 
  at Xamarin.Forms.Platform.iOS.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x00032] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Platform.cs:240 
  at Xamarin.Forms.Platform.iOS.VisualElementPackager.OnChildAdded (Xamarin.Forms.VisualElement view) [0x0003e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:119 
  at Xamarin.Forms.Platform.iOS.VisualElementPackager.Load () [0x0001e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:51 
  at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x0012e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementRenderer.cs:283 
  at Xamarin.Forms.Platform.iOS.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.iOS.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementRenderer.cs:158 
  at Xamarin.Forms.Platform.iOS.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x00032] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Platform.cs:240 
  at Xamarin.Forms.Platform.iOS.VisualElementPackager.OnChildAdded (Xamarin.Forms.VisualElement view) [0x0003e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:119 
  at Xamarin.Forms.Platform.iOS.VisualElementPackager.Load () [0x0001e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\VisualElementPackager.cs:51 
  at Xamarin.Forms.Platform.iOS.PageRenderer.ViewDidLoad () [0x0008f] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Renderers\PageRenderer.cs:251 
  at (wrapper managed-to-native) ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper(intptr,intptr)
  at UIKit.UIViewController.get_View () [0x0002a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/16.4.0.15/src/Xamarin.iOS/UIKit/UIViewController.g.cs:2938 
  at Xamarin.Forms.Platform.iOS.PageRenderer.get_NativeView () [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Renderers\PageRenderer.cs:103 
  at Xamarin.Forms.Platform.iOS.PageRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x0003d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Renderers\PageRenderer.cs:119 
  at Xamarin.Forms.Platform.iOS.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x00032] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Platform.cs:240 
  at Xamarin.Forms.Platform.iOS.ShellSectionRootRenderer.SetPageRenderer (Xamarin.Forms.Page page, Xamarin.Forms.ShellContent shellContent) [0x00013] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Renderers\ShellSectionRootRenderer.cs:497 
  at Xamarin.Forms.Platform.iOS.ShellSectionRootRenderer.LoadRenderers () [0x0009c] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Renderers\ShellSectionRootRenderer.cs:244 
  at Xamarin.Forms.Platform.iOS.ShellSectionRootRenderer.ViewDidLoad () [0x00077] in D:\a\1\s\Xamarin.Forms.Platform.iOS\Renderers\ShellSectionRootRenderer.cs:81 
  at (wrapper managed-to-native) UIKit.UIApplication.xamarin_UIApplicationMain(int,intptr,intptr,intptr,intptr&)
  at UIKit.UIApplication.UIApplicationMain (System.Int32 argc, System.String[] argv, System.IntPtr principalClassName, System.IntPtr delegateClassName) [0x00008] in /Library/Frameworks/Xamarin.iOS.framework/Versions/16.4.0.15/src/Xamarin.iOS/UIKit/UIApplication.cs:58 
  at UIKit.UIApplication.Main (System.String[] args, System.Type principalClass, System.Type delegateClass) [0x0003b] in /Library/Frameworks/Xamarin.iOS.framework/Versions/16.4.0.15/src/Xamarin.iOS/UIKit/UIApplication.cs:94 
  at Forms9Issue.iOS.Application.Main (System.String[] args) [0x00001] in C:\Users\mattheww\source\repos\Forms9Issue\Forms9Issue\Forms9Issue.iOS\Main.cs:17 

Basic Information

  • Version with issue: 2.4.9

  • Last known good version: Unknown

  • IDE: Visual Studio 2022 version 17.7.5 on Windows 10.0.19045 Build 19045

  • Platform Target Frameworks:

    • iOS: 8.0, 16.4
  • Nuget Packages: Forms9Patch, Xamarin.Forms, Xamarin.Essentials

  • Affected Devices: All, including simulators, as far as I can tell

Reproduction Link

https://github.com/mattheww-skyward/forms9patch-label-nullref

Workaround

None as yet besides using a regular label.

It's possible that hiding/showing the ShellContent, which seems to be a necessary step, is the wrong approach and could be avoided entirely.

Notes

_currentDrawState is null on line 47 of LabelRenderer.DrawLabel().

As best I can tell, that implies that OnElementChanged() must not have been called, or called with a null NewElement. So I think it should be sufficient to move the _currentDrawState.IsBlank check to the end, or to add an explicit null check as is done in Android's LabelRenderer.DrawLabel()?

I'd be happy to create a pull request, but I've been having trouble building the solution to confirm my theory.