Crash on IOS adding items to an ObservableCollection after Render
owaits opened this issue · 7 comments
Description
I am getting a crash in IOS when adding items to an observable collection after the observable collection has been displayed in a CollectionView. I have an observable collection that has a binding to the CollectionView. When I try to clear the observable collection and then add new items the app crashes in IOS but works fine for Android.
Steps to Reproduce
I am not entirely sure of how you repro this, it does happen consistently in my app but there is a complex series of events first. I will attempt to put together a simple example to repro this. For now here is the code I believe to cause the crash and the stack trace from the output after the crash ocurrs.
public ObservableCollection<TItem> Items { get; set; } = new ObservableCollection<TItem>();
public void Load()
{
Items.Clear();
if(updateManyHandler != null)
{
foreach(var item in updateManyHandler())
{
Items.Add(item);
}
}
if (updateHandler != null)
{
Item = updateHandler(Id);
Items.Add(Item);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Item)));
}
LoadPartnerAdvert();
IsLoading = false;
}
Version with bug
Preview 13 (current)
Last version that worked well
Preview 12
Affected platforms
iOS
Affected platform versions
iPadIOS 15
Did you find any workaround?
Not yet
Relevant log output
2022-02-17 14:29:40.878 Xamarin.PreBuilt.iOS[3837:3357137] *** Assertion failure in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:collectionViewAnimator:], UICollectionView.m:8456
[0:] An error occurred: 'Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: attempt to insert item 0 into section 0, but there are only 0 items in section 0 after the update
Native stack trace:
0 CoreFoundation 0x0000000184a22060 B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 626784
1 libobjc.A.dylib 0x000000019d096f54 objc_exception_throw + 60
2 Foundation 0x00000001862db6cc D59C6975-5AF2-37BC-93BE-43B80B4293A5 + 1246924
3 UIKitCore 0x000000018721b65c 8388EB03-002B-3B35-A78A-6A022894292E + 4114012
4 UIKitCore 0x00000001874c4574 8388EB03-002B-3B35-A78A-6A022894292E + 6903156
5 UIKitCore 0x0000000186edb6e4 8388EB03-002B-3B35-A78A-6A022894292E + 706276
6 Xamarin.PreBuilt.iOS 0x0000000102b8540c Xamarin.PreBuilt.iOS + 87052
7 Xamarin.PreBuilt.iOS 0x0000000102ea5e4c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2112228
8 Xamarin.PreBuilt.iOS 0x0000000102e9b438 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2068688
9 Xamarin.PreBuilt.iOS 0x0000000102e98ffc _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2059412
10 Xamarin.PreBuilt.iOS 0x0000000102b854c8 Xamarin.PreBuilt.iOS + 87240
11 libdispatch.dylib 0x0000000184694660 A5CBAAB3-E389-3548-BAAC-FAB18411B94A + 18016
12 libdispatch.dylib 0x00000001846a2b60 _dispatch_main_queue_callback_4CF + 944
13 CoreFoundation 0x00000001849dacd4 B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 335060
14 CoreFoundation 0x0000000184994eac B2D21CFD-378C-36D5-BAF7-3F70599CFEFC + 48812
15 CoreFoundation 0x00000001849a83b8 CFRunLoopRunSpecific + 600
16 GraphicsServices 0x00000001a033838c GSEventRunModal + 164
17 UIKitCore 0x00000001873486a8 8388EB03-002B-3B35-A78A-6A022894292E + 5346984
18 UIKitCore 0x00000001870c77f4 UIApplicationMain + 2092
19 Xamarin.PreBuilt.iOS 0x0000000102ea692c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2115012
20 Xamarin.PreBuilt.iOS 0x0000000102ea5b34 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2111436
21 Xamarin.PreBuilt.iOS 0x0000000102e9b33c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2068436
22 Xamarin.PreBuilt.iOS 0x0000000102e9983c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2061524
23 Xamarin.PreBuilt.iOS 0x0000000102e6bb38 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1873872
24 Xamarin.PreBuilt.iOS 0x0000000102db73d4 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1134700
25 Xamarin.PreBuilt.iOS 0x0000000102dbe2e0 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1163128
26 Xamarin.PreBuilt.iOS 0x0000000102d7e74c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 902116
27 Xamarin.PreBuilt.iOS 0x0000000102d89008 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 945312
28 Xamarin.PreBuilt.iOS 0x0000000102ea692c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2115012
29 Xamarin.PreBuilt.iOS 0x0000000102ea5b34 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2111436
30 Xamarin.PreBuilt.iOS 0x0000000102e9b33c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2068436
31 Xamarin.PreBuilt.iOS 0x0000000102e9983c _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2061524
32 Xamarin.PreBuilt.iOS 0x0000000102e6bb38 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1873872
33 Xamarin.PreBuilt.iOS 0x0000000102db73d4 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1134700
34 Xamarin.PreBuilt.iOS 0x0000000102dbcddc _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1157748
35 Xamarin.PreBuilt.iOS 0x0000000102e708f4 _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 1893772
36 Xamarin.PreBuilt.iOS 0x0000000102bc6800 xamarin_get_original_working_directory_path + 3672
37 Xamarin.PreBuilt.iOS 0x0000000102eda5dc _ZNK3icu6number23NumberFormatterSettingsINS0_24LocalizedNumberFormatterEE10toSkeletonER10UErrorCode + 2327156
38 dyld 0x000000010325da24 start + 520
'. Callstack: ' at ObjCRuntime.Runtime.ThrowNSException(IntPtr ns_exception)
at ObjCRuntime.Runtime.throw_ns_exception(IntPtr exc)
at UIKit.UICollectionView.InsertItems(NSIndexPath[] indexPaths)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.<>c__DisplayClass36_0.<Add>b__0()
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.Update(Action update, NotifyCollectionChangedEventArgs args)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.Add(NotifyCollectionChangedEventArgs args)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.CollectionChanged(NotifyCollectionChangedEventArgs args)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.CollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
at System.Collections.ObjectModel.ObservableCollection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedAction action, Object item, Int32 index)
at System.Collections.ObjectModel.ObservableCollection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].InsertItem(Int32 index, Speaker item)
at System.Collections.ObjectModel.Collection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Add(Speaker item)
at WordAlive.ViewModels.EventDataModel`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Load() in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\ViewModels\EventDataModel.cs:line 121
at WordAlive.ViewModels.EventDataModel`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<UpdateManager_UpdateFinished>b__19_0() in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\ViewModels\EventDataModel.cs:line 92
at Microsoft.Maui.Dispatching.Dispatcher.<>c__DisplayClass7_0.<DispatchImplementation>b__0()
at CoreFoundation.DispatchQueue.static_dispatcher_to_managed(IntPtr context)
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
at WordAlive.Program.Main(String[] args) in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\Platforms\iOS\Program.cs:line 13
--- End of stack trace from previous location ---
at UIKit.UICollectionView.InsertItems(NSIndexPath[] indexPaths)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.<>c__DisplayClass36_0.<Add>b__0()
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.Update(Action update, NotifyCollectionChangedEventArgs args)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.Add(NotifyCollectionChangedEventArgs args)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.CollectionChanged(NotifyCollectionChangedEventArgs args)
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.CollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
at System.Collections.ObjectModel.ObservableCollection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedAction action, Object item, Int32 index)
at System.Collections.ObjectModel.ObservableCollection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].InsertItem(Int32 index, Speaker item)
at System.Collections.ObjectModel.Collection`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Add(Speaker item)
at WordAlive.ViewModels.EventDataModel`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Load() in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\ViewModels\EventDataModel.cs:line 121
at WordAlive.ViewModels.EventDataModel`1[[MWC.BL.Speaker, MWC.Core.MD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<UpdateManager_UpdateFinished>b__19_0() in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\ViewModels\EventDataModel.cs:line 92
at Microsoft.Maui.Dispatching.Dispatcher.<>c__DisplayClass7_0.<DispatchImplementation>b__0()
at CoreFoundation.DispatchQueue.static_dispatcher_to_managed(IntPtr context)
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
at WordAlive.Program.Main(String[] args) in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\Platforms\iOS\Program.cs:line 13
--- End of stack trace from previous location ---
at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
at WordAlive.Program.Main(String[] args) in D:\ofilms.visualstudio.com\Repos\WordAliveApp\Trunk\WordAlive\Platforms\iOS\Program.cs:line 13
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)'
The app has been terminated.
This bug is connected to VS issue https://developercommunity.visualstudio.com/t/android-and-ios-device-debugging-no-longer-availab/1668207 as after the crash you can no longer debug the app through HotReload in Visual Studio. To get debugging working again you need to delete all the files from %Temp%.
Hi @owaits. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
FWIW, I think I have find the root cause of this and many other issues on iOS CollectionView. In short - the Data Source is bound twice when creating the view, causing all sorts of mad behavior (because the first registered ObservableItemsSource
's callbacks are called first, but it's the second ObservableItemsSource
's properties that are consulted by the UICollectionView
)
I haven't gone in-depth with the investigation, but the two registrations seem to originate in ElementHandler.SetVirtualView
:
Trace 1
...
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource..ctor(IEnumerable itemSource, UICollectionViewController collectionViewController, Int32 group)
at Microsoft.Maui.Controls.Handlers.Items.ItemsSourceFactory.Create(IEnumerable itemsSource, UICollectionViewController collectionViewController)
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CreateItemsViewSource()
at Microsoft.Maui.Controls.Handlers.Items.GroupableItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CreateItemsViewSource()
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ViewDidLoad()
at ObjCRuntime.Messaging.NativeHandle_objc_msgSendSuper(IntPtr , IntPtr )
at UIKit.UIViewController.get_View()
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewHandler`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CreateNativeView()
at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[UIKit.UIView, Xamarin.iOS, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]].OnCreateNativeView()
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewHandler`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCreateNativeView()
at Microsoft.Maui.Handlers.ViewHandler.OnCreateNativeElement()
at Microsoft.Maui.Handlers.ElementHandler.CreateNativeElement()
at Microsoft.Maui.Handlers.ElementHandler.SetVirtualView(IElement view)
...
Trace 2
...
at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource..ctor(IEnumerable itemSource, UICollectionViewController collectionViewController, Int32 group)
at Microsoft.Maui.Controls.Handlers.Items.ItemsSourceFactory.Create(IEnumerable itemsSource, UICollectionViewController collectionViewController)
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CreateItemsViewSource()
at Microsoft.Maui.Controls.Handlers.Items.GroupableItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CreateItemsViewSource()
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].UpdateItemsSource()
at Microsoft.Maui.Controls.Handlers.Items.GroupableItemsViewController`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].UpdateItemsSource()
at Microsoft.Maui.Controls.Handlers.Items.ItemsViewHandler`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MapItemsSource(ItemsViewHandler`1 handler, ItemsView itemsView)
at Microsoft.Maui.Controls.Handlers.Items.SelectableItemsViewHandler`1[[Microsoft.Maui.Controls.GroupableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MapItemsSource(SelectableItemsViewHandler`1 handler, SelectableItemsView itemsView)
at Microsoft.Maui.PropertyMapper`2.<>c__DisplayClass5_0[[Microsoft.Maui.Controls.CollectionView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Handlers.Items.CollectionViewHandler, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<Add>b__0(IElementHandler h, IElement v)
at Microsoft.Maui.PropertyMapper.UpdatePropertyCore(String key, IElementHandler viewHandler, IElement virtualView)
at Microsoft.Maui.PropertyMapper.UpdateProperties(IElementHandler viewHandler, IElement virtualView)
at Microsoft.Maui.Handlers.ElementHandler.SetVirtualView(IElement view)
...
Hotfix
Since the second call is very easy to eliminate by simply removing the property mapping, I've just added the following to app startup and all problems appear to be gone:
// fix a bug in MAUI Preview 13, where the ItemsSource is registered twice, causing all sorts of weird issues
Microsoft.Maui.Controls.Handlers.Items.CollectionViewHandler.CollectionViewMapper[ItemsView.ItemsSourceProperty.PropertyName] = (_, _) => {};
Sorry for the delay in replying (I have been moving house). I have managed to confirm that the hotfix suggested by @ssimek does resolve the issue I was facing. Do you think you now have enough info to fix this bug or do you still need me to try and put together a sample app that reproduces the issue?
This is also broken on Android in RC1. Adding items to a an ObservableCollection bound to a ListView crashes on android, but not on windows. Using a CollectionView fixes the issue. Worked on both List/Collectionview on Android/Windows in Preview 14.
If you remove the Clear() does it work?