Xamarin.Forms icon indicating copy to clipboard operation
Xamarin.Forms copied to clipboard

[Bug] [iOS] CollectionView iOS inner crash while adding items to group, items aren't displayed

Open bondarenkod opened this issue 4 years ago • 39 comments

Description

I was testing the latest build of XamarinForms when I realized that there is an issue related to a group's item manipulation on the iOS platform. I can't reproduce this error on the Android platform. I've also tried to use ObservableRangeCollection without any noticeable difference from the default ObservableCollection. There are also a few lines of iOS inner exception message:

2021-01-02 14:32:21.361034+0200 xf_cv_range.iOS[3615:42647] *** Assertion failure in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:collectionViewAnimator:], UICollectionView.m:7294
[0:] Foundation.MonoTouchException: Objective-C exception thrown.  Name: NSInternalInconsistencyException Reason: Invalid update: invalid number of sections.  The number of sections contained in the collection view after the update (1) must be equal to the number of sections contained in the collection view before the update (1), plus or minus the number of sections inserted or deleted (1 inserted, 0 deleted).

Full output log is here 02_01_2021__14_40_13__e09b3d8b-4a6c-4d31-b7c0-9f047d3c1dfa.txt

I will add any additional info if needed.

Steps to Reproduce

  1. Use Xamarin.Forms 4.8.0.1821
  2. Add empty group to the ObservableCollection, then add items to the group:
var group = new Group();
Items.Add(group);
foreach (var item in items)
    group.Add(item);
  1. Run the app.

If you are using my demo project:

  1. Run the app on any iOS device/simulator.
  2. Switch to the second tab (Browse)
  3. Apply pull-to-refresh on the CV.
  4. You can downgrade XF version to 4.8.0.1687 and repeat the test to see that now it's working.

Expected Behavior

Added items are presented (visible) on the screen.

Actual Behavior

Added items aren't presented (visible) on the screen. You can see the exception in the VS's output window.

Basic Information

  • Version with issue: Xamarin.Forms 4.8.0.1821 (latest for today)
  • Last known good version: Xamarin.Forms 4.8.0.1687
  • Platform Target Frameworks:
    • iOS: 14.2
    • Android: No issue on this platform

Environment

not applicable

Build Logs

not applicable

Screenshots

Good result (XF 4.8.0.1687): https://user-images.githubusercontent.com/3184414/103457346-2ec98280-4d07-11eb-81e1-caabdf11bce0.mp4 Bad result (XF 4.8.0.1821): https://user-images.githubusercontent.com/3184414/103457371-6df7d380-4d07-11eb-8916-0615bedaae21.mp4

Reproduction Link

https://github.com/bondarenkod/xf_cv_group_add_range_bug

Workaround

Downgrade to Xamarin.Forms 4.8.0.1687

bondarenkod avatar Jan 02 '21 12:01 bondarenkod

This is happening in Xamarin Forms 5.0.0.1829-pre6 as well. Code was previously working on older versions of Xamarin <= 4.8.0.1687.

This is only triggered with IsGrouped="True"

mphill avatar Jan 05 '21 19:01 mphill

Bind your list after the for statement. If you add itens to your list as you bind it to your collectionView the app is going to crash

AdrianoBinhara avatar Mar 05 '21 13:03 AdrianoBinhara

I think issue with ObservableCollection. Generic List works on iOS on XF>4.8.0.1687, but it doesn't bind CollectionView IsGrouped on Android. ObservableCollection is important part of MVVM, it should be fixed. Downgraded XF 4.8.1687 for working on both platforms for now.

kgouraw avatar Mar 18 '21 14:03 kgouraw

@kgouraw nope, the problem inside the synchronizer.

bondarenkod avatar Mar 19 '21 15:03 bondarenkod

Are there any updates on this? I know it's only been reported recently but it really slows down our dev/test cycles.

vniehues avatar Mar 30 '21 12:03 vniehues

In version 5.0.0.2012 no changes, we are waiting

RenatGaliew avatar Apr 16 '21 09:04 RenatGaliew

I was actually able to work around this issue by using the ObservableRangeCollection and using it's AddRange() method. It might have been a different underlying issue though.

vniehues avatar Apr 16 '21 19:04 vniehues

I was actually able to work around this issue by using the ObservableRangeCollection and using it's AddRange() method. It might have been a different underlying issue though.

Let's try by AddRange. I will write how the results will be.

RenatGaliew avatar Apr 19 '21 04:04 RenatGaliew

I was actually able to work around this issue by using the ObservableRangeCollection and using it's AddRange() method. It might have been a different underlying issue though.

The result is negative. Did not help. Let's try to think of another solution.

RenatGaliew avatar Apr 19 '21 05:04 RenatGaliew

@RenatGaliew try to use dynamic data

bondarenkod avatar Apr 19 '21 17:04 bondarenkod

@bondarenkod my data is already dynamic, once the data is loaded everything is fine, then after switching to another page and returning to the current one, an error crashes and nothing more will be added, it crashes on the add method

RenatGaliew avatar Apr 20 '21 08:04 RenatGaliew

I am seeing the same thing, and I am also using the Dynamic Data package to operate the collection.

PCDK avatar Apr 20 '21 10:04 PCDK

@RenatGaliew oh, sorry, I meant this https://github.com/reactivemarbles/DynamicData

bondarenkod avatar Apr 20 '21 15:04 bondarenkod

Any working workaround?

kalprajkakani avatar May 04 '21 17:05 kalprajkakani

Still Crashing !! Xamarin Forms : 5.0.0.2012

samirgcofficial avatar May 22 '21 11:05 samirgcofficial

This happens when grouped items are added to an ObservableCollection that is bound to a CollectionView. It works fine up to XF 4.8.0.1687. Any version since then generates the error in the original post. As a workaround, I don't bind the CollectionView in xaml. My CollectionView is inside a RefreshView, so I use code behind PropertyChanged event "IsRefreshing". If true then RemoveBinding. If false then SetBinding. Basically removing the binding before populating the collection, then adding the binding once the collection is fully populated. In the ViewModel, don't reuse the ObservableCollection with the .Clear method. Always instantiate the variable as a new ObservableCollection. I battled this for days, and this was the only way I could avoid the error.

Nadraw avatar May 25 '21 20:05 Nadraw

await Task.Delay(300);
//Then again bind the cleaned Observable collection object. This trick just worked for me.

samirgcofficial avatar May 26 '21 00:05 samirgcofficial

I worked around the issue by adding a private method to do the updating where the binding is removed/added. Everywhere in the code where I previously updated my ObservableCollection I now instead call the new private method using a new ObservableCollection each time.

before:

MeetingLocationsGrouped.Clear();
MeetingLocationsGrouped = new ObservableCollection<Grouping<DayOfWeek, MeetingLocationPageModel>>(result);

after:

UpdateMeetingLocationsGrouped(new ObservableCollection<Grouping<DayOfWeek, MeetingLocationPageModel>>());
UpdateMeetingLocationsGrouped(new ObservableCollection<Grouping<DayOfWeek, MeetingLocationPageModel>>(result));
private void UpdateMeetingLocationsGrouped(ObservableCollection<Grouping<DayOfWeek, MeetingLocationPageModel>> data)
{
     _meetingLocationsCollectionView.RemoveBinding(CollectionView.ItemsSourceProperty);
     MeetingLocationsGrouped = data;
     _meetingLocationsCollectionView.SetBinding(CollectionView.ItemsSourceProperty, nameof(this.MeetingLocationsGrouped));
}

gurkan8941 avatar May 31 '21 11:05 gurkan8941

I've just tested this bug again, this time directly in XF sources, it seems like the issue is still there and 100% reproducible. For those who are stuck with it, it can be fixed by adding a small delay between .Clear() and .Add(). In my demo adding even await Task.Delay(100); eliminated the crash.

var itemsToAdd = Enumerable.Range(0, 20).Select(x => new Member($"Guardian-{x}")).ToArray();
var group = new ObservableTeam("Excalibur", new List<Member>(0));
itemsSource.Clear();
await Task.Delay(100);
itemsSource.Add(group);
foreach (var item in itemsToAdd)
    group.Add(item);				

https://user-images.githubusercontent.com/3184414/121402297-5f6eb180-c962-11eb-88de-800b1dccd450.mp4

bondarenkod avatar Jun 09 '21 17:06 bondarenkod

Adding .LayoutIfNeeded() into L:\src_github\xf500\Xamarin.Forms.Platform.iOS\CollectionView\ObservableGroupedSource.cs eliminated the crash.

void Reload()
{
    ResetGroupTracking();

    _collectionView.ReloadData();
    _collectionView.LayoutIfNeeded();
    _collectionView.CollectionViewLayout.InvalidateLayout();
}

But it continues writing such messages to the console (the same in the attached demo, so I'll skip it for now):

2021-06-09 23:47:34.850570+0300 XamarinFormsControlGalleryiOS[33463:330322] [UICollectionView] Invalid update:
 invalid number of items in section 0.  
The number of items contained in an existing section after the update (1)
 must be equal to the number of items contained in that section before the update (1), 
plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) 
and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). -
 will perform reloadData. UICollectionView instance: <UICollectionView: 0x7ffaa5057800; 
frame = (0 0; 390 753); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = 
<NSArray: 0x600001cb48d0>; layer = <CALayer: 0x6000016ef8a0>; contentOffset: {0, 0}; contentSize: {390, 65}; adjustedContentInset: {0, 0, 0, 0}; layout: <Xamarin_Forms_Platform_iOS_ListViewLayout: 
0x7ffaa601cc80>; dataSource: <Xamarin_Forms_Platform_iOS_GroupableItemsViewController_1: 
0x7ffaa601d4f0>>; currentUpdate: [UICollectionViewUpdate - 0
x7ffaa3d6a890: old:<UICollectionViewData: 0x600002dc1fe0> 
new<UICollectionViewData: 0x600002df83c0> items:<(
    "I(0,0)"
)>]

bondarenkod avatar Jun 09 '21 18:06 bondarenkod

I've opened up a similar issue for this, when the CollectionView is Grouped and I try to .Add() multiple items. Very frustrating. https://github.com/xamarin/Xamarin.Forms/issues/14362

iupchris10 avatar Jun 22 '21 15:06 iupchris10

Adding “await Task.Delay(100);”, or even 1ms helps, but does introduce a strange behavior when users scrolls the list. It seems to flick and get very slow - almost unusable, in my case. Another issue is the pull to refresh. It stopped working.

Going back to old version of XF. Thanks for help.

lndalmd avatar Oct 05 '21 10:10 lndalmd

Seems like some people reported this as still not working unfortunately.

jfversluis avatar Jun 23 '22 11:06 jfversluis

Everyone still experiencing this and watching this issue, a PR for this is open now, would you be able to grab the NuGet as described here and let us know if this fixes this issue? That will greatly speed up the review process. Make sure to take the exact version number that is listed on the PR.

Besides verifying if this particular issue is fixed also be sure to check other scenarios in the same area to make sure that this fix doesn't accidentally has side-effects 🙂

Thanks!

jfversluis avatar Jun 24 '22 13:06 jfversluis

Anyone able to test this?

jfversluis avatar Jul 11 '22 13:07 jfversluis

@jfversluis I've been working with a customer who is still seeing this issue. They have helped create a repro sample app which consistently crashes ReproSample

BenBtg avatar Jul 14 '22 16:07 BenBtg

I'm sorry guys, I'm currently closing release, so I'm not able to pay any attention to this issue nor this or the next week.

bondarenkod avatar Jul 14 '22 19:07 bondarenkod

Anyone able to test this?

@jfversluis I have tested the PR. My problems with the CollectionView were solved with it!

SEngelsKTS avatar Aug 18 '22 13:08 SEngelsKTS

@jfversluis ?? Where to find the NuGet? Nothing in the DevOps artifact. Sorry. I am newbie, may be making a stupid mistake.

kazutsugu avatar Aug 23 '22 14:08 kazutsugu

@jfversluis ?? Where to find the NuGet? Nothing in the DevOps artifact. Sorry. I am newbie, may be making a stupid mistake.

You have to add an additional package source (https://aka.ms/forms-prs/index.json), then the NuGet will be found.

SEngelsKTS avatar Aug 24 '22 08:08 SEngelsKTS