Xamarin.Forms
Xamarin.Forms copied to clipboard
[Bug] ArgumentOutOfRangeException on iOS when removing last item from a collection view with an observable ItemsSource
Description
There is a regression in XF 5 on iOS where removing the last item in an observable collection which is serving as the ItemSource for a collection view will cause a crash due to an ArgumentOutOfRangeException. Specifically, the regression was introduced in 5.0.0.1874 by this change: https://github.com/xamarin/Xamarin.Forms/commit/2dfbf5f5b9ca2637828136abbdc6b50190de5fab
This changeset modified ObservableItemsSource.CollectionChanged
and added the following line:
CollectionView.NumberOfItemsInSection(_section);
But this is happening before the internal state of ObservableItemsSource
is updated--namely ItemCount
. This is problematic because checking the number of items in the section will indirectly invoke ItemsViewController.CheckForEmptySource
which checks ItemsSource.ItemCount
--since this property hasn't been updated yet, it causes two problems:
- When adding the first item to the collection, the empty view will still be visible (because
ItemCount
will still be 0) - When removing the last item from the collection,
ItemCount
will still be 1 which will ultimately lead to an attempt to determine the cell size which will attempt to access the first item in an empty collection (causing the ArgumentOutOfRangeException).
Here's an example of the stack trace of the crash:
Unhandled managed exception: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index (System.ArgumentOutOfRangeException)
at System.Collections.Generic.List`1[T].get_Item (System.Int32 index) [0x00009] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:161
at System.Collections.Generic.List`1[T].System.Collections.IList.get_Item (System.Int32 index) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:188
at redacted.Data.ViewModels.RefreshableBaseCollectionViewModel`2[TModel,TViewModel].get_Item (System.Int32 index) [0x00000] in /Users/dpfeiffer/repos/redacted.app2/redacted.Data/View Models/RefreshableBaseCollectionViewModel.cs:74
at Xamarin.Forms.Platform.iOS.ObservableItemsSource.ElementAt (System.Int32 index) [0x0000f] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:240
at Xamarin.Forms.Platform.iOS.ObservableItemsSource.get_Item (System.Int32 index) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:40
at Xamarin.Forms.Platform.iOS.ObservableItemsSource.get_Item (Foundation.NSIndexPath indexPath) [0x00019] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:96
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].UpdateTemplatedCell (Xamarin.Forms.Platform.iOS.TemplatedCell cell, Foundation.NSIndexPath indexPath) [0x00024] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:250
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].CreateMeasurementCell (Foundation.NSIndexPath indexPath) [0x0007b] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:587
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].GetPrototype () [0x0005d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:362
at Xamarin.Forms.Platform.iOS.ItemsViewLayout.DetermineCellSize () [0x00060] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewLayout.cs:211
at Xamarin.Forms.Platform.iOS.ListViewLayout.ConstrainTo (CoreGraphics.CGSize size) [0x0001e] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ListViewLayout.cs:16
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].CheckForEmptySource () [0x0005d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:125
at Xamarin.Forms.Platform.iOS.ItemsViewController`1[TItemsView].NumberOfSections (UIKit.UICollectionView collectionView) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ItemsViewController.cs:231
at (wrapper managed-to-native) ObjCRuntime.Messaging.nint_objc_msgSend_nint(intptr,intptr,System.nint)
at UIKit.UICollectionView.NumberOfItemsInSection (System.nint section) [0x0000d] in /Users/builder/azdo/_work/1/s/xamarin-macios/src/build/ios/native/UIKit/UICollectionView.g.cs:552
at Xamarin.Forms.Platform.iOS.ObservableItemsSource.CollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:115
at Xamarin.Forms.Platform.iOS.ObservableItemsSource.CollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x0002d] in D:\a\1\s\Xamarin.Forms.Platform.iOS\CollectionView\ObservableItemsSource.cs:108
at (wrapper delegate-invoke) <Module>.invoke_void_object_NotifyCollectionChangedEventArgs(object,System.Collections.Specialized.NotifyCollectionChangedEventArgs)
at Float.Core.ViewModels.BaseCollectionViewModel`2[TModel,TViewModel].<OnElementsChanged>b__28_0 () [0x0000b] in /Users/jenkins/.jenkins/jobs/Float-NuGet-Core/workspace/Float.Core/ViewModels/BaseCollectionViewModel.cs:275
at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Users/builder/azdo/_work/1/s/xamarin-macios/src/Foundation/NSAction.cs:152
--- End of stack trace from previous location where exception was thrown ---
at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:86
at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0000e] in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:65
at redacted.iOS.Application.Main (System.String[] args) [0x00000] in /Users/dpfeiffer/repos/redacted.app2/redacted.iOS/Main.cs:33
This exception was specifically generated by starting with an observable collection, adding one item, and then removing that one item. You'll notice from the stack trace that despite there being no elements in the collection, XF attempts to create the first cell to measure for layout purposes (because it doesn't realize the list is now empty).
Basic Information
- Version with issue: 5.0.0.1874
- Last known good version: 4.8.0.1821
- Platform Target Frameworks:
- iOS: 14.3
- Android: N/A
- UWP: N/A
- Android Support Library / AndroidX Version: N/A
- NuGet Packages: N/A
- Affected Devices: N/A
Environment
Show/Hide Visual Studio info
=== Visual Studio Enterprise 2019 for Mac ===
Version 8.9.6 (build 6)
Installation UUID: 396335d3-ed5f-4c3b-8739-b2428955e66e
GTK+ 2.24.23 (Raleigh theme)
Xamarin.Mac 6.18.0.23 (d16-6 / 088c73638)
Package version: 612000125
=== Mono Framework MDK ===
Runtime:
Mono 6.12.0.125 (2020-02/8c552e98bd6) (64-bit)
Package version: 612000125
=== Roslyn (Language Service) ===
3.9.0-6.21152.10+c10f884b30737542ddd84ca889a4aad9281ce210
=== NuGet ===
Version: 5.8.0.6860
=== .NET Core SDK ===
SDK: /usr/local/share/dotnet/sdk/5.0.202/Sdks
SDK Versions:
5.0.202
5.0.201
5.0.103
5.0.102
5.0.101
5.0.100
3.1.408
3.1.407
3.1.406
3.1.405
3.1.404
3.1.402
3.1.401
3.1.302
3.1.301
3.1.300
3.1.200
3.1.101
3.1.100
3.0.101
3.0.100
2.1.701
2.1.505
2.1.504
2.1.503
2.1.302
2.1.301
2.1.4
2.0.0
1.0.3
MSBuild SDKs: /Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/Sdks
=== .NET Core Runtime ===
Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
5.0.5
5.0.4
5.0.3
5.0.2
5.0.1
5.0.0
3.1.14
3.1.13
3.1.12
3.1.11
3.1.10
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.2
3.1.1
3.1.0
3.0.1
3.0.0
2.1.23
2.1.22
2.1.21
2.1.20
2.1.19
2.1.18
2.1.16
2.1.15
2.1.14
2.1.13
2.1.12
2.1.9
2.1.8
2.1.7
2.1.2
2.1.1
2.0.5
2.0.0
1.1.1
1.0.4
=== .NET Core 3.1 SDK ===
SDK: 3.1.408
=== Xamarin.Profiler ===
Version: 1.6.13.11
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler
=== Updater ===
Version: 11
=== Apple Developer Tools ===
Xcode 12.4 (17801)
Build 12D4e
=== Xamarin.Mac ===
Version: 7.8.2.5 (Visual Studio Enterprise)
Hash: 3836759d4
Branch: d16-9
Build date: 2021-02-10 17:56:43-0500
=== Xamarin.Android ===
Version: 11.2.2.1 (Visual Studio Enterprise)
Commit: xamarin-android/d16-9/877f572
Android SDK: /Users/dpfeiffer/Library/Android/sdk
Supported Android versions:
4.4 (API level 19)
5.0 (API level 21)
5.1 (API level 22)
6.0 (API level 23)
7.0 (API level 24)
7.1 (API level 25)
8.1 (API level 27)
SDK Tools Version: 26.1.1
SDK Platform Tools Version: 29.0.2
SDK Build Tools Version: 29.0.2
Build Information:
Mono: 5e9cb6d
Java.Interop: xamarin/java.interop/d16-9@54f8c24
ProGuard: Guardsquare/proguard/v7.0.1@912d149
SQLite: xamarin/sqlite/3.34.1@daff8f4
Xamarin.Android Tools: xamarin/xamarin-android-tools/d16-9@d210f11
=== Microsoft OpenJDK for Mobile ===
Java SDK: /Users/dpfeiffer/Library/Developer/Xamarin/jdk/microsoft_dist_openjdk_1.8.0.25
1.8.0-25
Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL
=== Android SDK Manager ===
Version: 16.9.0.22
Hash: a391de2
Branch: remotes/origin/d16-9~2
Build date: 2021-03-24 08:30:26 UTC
=== Android Device Manager ===
Version: 16.9.0.17
Hash: fc2b3db
Branch: remotes/origin/dev/jmt/d16-9bump~1
Build date: 2021-03-24 08:30:44 UTC
=== Xamarin.iOS ===
Version: 14.14.2.5 (Visual Studio Enterprise)
Hash: 3836759d4
Branch: d16-9
Build date: 2021-02-10 17:56:44-0500
=== Xamarin Designer ===
Version: 16.9.0.323
Hash: 1b4790c08
Branch: remotes/origin/d16-9
Build date: 2021-03-31 05:12:20 UTC
=== Build Information ===
Release ID: 809060006
Git revision: 47cf16e38721a785b8e2296ce6716502f34261ac
Build date: 2021-04-07 07:23:18-04
Build branch: release-8.9
Xamarin extensions: 47cf16e38721a785b8e2296ce6716502f34261ac
=== Operating System ===
Mac OS X 10.15.7
Darwin 19.6.0 Darwin Kernel Version 19.6.0
Tue Jan 12 22:13:05 PST 2021
root:xnu-6153.141.16~1/RELEASE_X86_64 x86_64
=== Enabled user installed extensions ===
XAML Styler 2.0.1
Build Logs
Screenshots
Reproduction Link
N/A
Workaround
None.
This might be related to the issue in #9632 -- but I opened a separate issue since the stack trace was different.
I think I managed to workaround this issue by setting IsVisible of collection view to false as soon as I know there are no items to display. XF 5.0
Any news about this issue? Facing that one... tried to downgrade to 4.8.0.1821 but I can't because of other issues (with RadioButton being experimental). Tried everything.. removing the collection, hiding the component,. Nothing has worked. Is there any fix coming?
I just encountered this same bug, I get ArgumentOutOfRangeExceptions out of simple .Clear() operations, XF 5.0.0.2291
I just encountered this same bug, I get ArgumentOutOfRangeExceptions out of simple .Clear() operations, XF 5.0.0.2291
@MAVREE Same issue here .Clear() seems less then reliable, I have swapped many of instances of .Clear() to .ReplaceRange() instead
I've replaced uses of the clear method with a different one where, depending on the number of items, it'll clear the collection (if more than 1 item is present) or replace the collection with a new one (if there is only 1 item in the collection). note that replacing the collection with a new one will break binding so you need to have something in place to notify the UI that the items source property has been changed.