The problem
Here is my state of affairs : I’ve a web page in my Maui utility with a CollectionView
certain to an ObservableCollection
. I dynamically add at a number of factors in my app gadgets to this Assortment by means of a customized WeakReferenceMessenger
.
Particularly, I’ve a button in the identical web page which triggers a number of message additions to the gathering.
Right here comes my situation : once I press this button on an android surroundings, the whole lot works simply high quality, I see my messages added to the gathering with none downside. However once I check it on iOS, both on an emulator or on a bodily machine, the applying crashes and sends me the next exception :
Exception
Goal-C exception thrown. Title: NSInternalInconsistencyException Cause: request for index path for world index 12 when there are solely 12 gadgets within the assortment view
Native stack hint:
0 CoreFoundation 0x0000000197c87228 7821F73C-378B-3A10-BE90-EF526B7DBA93 + 1155624
1 libobjc.A.dylib 0x0000000195121abc objc_exception_throw + 88
2 Basis 0x0000000196f85670 34DE055D-8683-380A-9198-C3347211D13D + 7988848
3 UIKitCore 0x000000019a790ff8 96636F64-106F-30C8-A780-82DCEBB0F443 + 3362808
4 UIKitCore 0x000000019a9363cc 96636F64-106F-30C8-A780-82DCEBB0F443 + 5088204
5 UIKitCore 0x000000019a9362d4 96636F64-106F-30C8-A780-82DCEBB0F443 + 5087956
6 UIKitCore 0x000000019a9688a0 96636F64-106F-30C8-A780-82DCEBB0F443 + 5294240
7 UIKitCore 0x000000019a9684ec 96636F64-106F-30C8-A780-82DCEBB0F443 + 5293292
8 UIKitCore 0x000000019a4912b4 96636F64-106F-30C8-A780-82DCEBB0F443 + 217780
9 UIKitCore 0x000000019a75eec8 96636F64-106F-30C8-A780-82DCEBB0F443 + 3157704
10 UIKitCore 0x000000019a75d06c 96636F64-106F-30C8-A780-82DCEBB0F443 + 3149932
11 UIKitCore 0x000000019aa1bcec 96636F64-106F-30C8-A780-82DCEBB0F443 + 6028524
12 UIKitCore 0x000000019aa1b9d0 96636F64-106F-30C8-A780-82DCEBB0F443 + 6027728
13 UBScoring 0x0000000104977648 xamarin_dyn_objc_msgSendSuper + 164
14 UBScoring 0x0000000104b332b0 do_icall + 200
15 UBScoring 0x0000000104b318f4 do_icall_wrapper + 348
16 UBScoring 0x0000000104b24e28 mono_interp_exec_method + 2580
17 UBScoring 0x0000000104b221dc interp_entry_from_trampoline + 656
18 UBScoring 0x0000000104949970 native_to_interp_trampoline + 112
19 UBScoring 0x0000000104b8d458 -[__MonoMac_NSAsyncActionDispatcher xamarinApplySelector] + 96
20 Basis 0x000000019685d574 34DE055D-8683-380A-9198-C3347211D13D + 484724
21 CoreFoundation 0x0000000197b7ca8c 7821F73C-378B-3A10-BE90-EF526B7DBA93 + 64140
22 CoreFoundation 0x0000000197b7c8a4 7821F73C-378B-3A10-BE90-EF526B7DBA93 + 63652
23 CoreFoundation 0x0000000197b7c700 7821F73C-378B-3A10-BE90-EF526B7DBA93 + 63232
24 CoreFoundation 0x0000000197b7d080 7821F73C-378B-3A10-BE90-EF526B7DBA93 + 65664
25 CoreFoundation 0x0000000197b7ec3c CFRunLoopRunSpecific + 572
26 GraphicsServices 0x00000001e4d5d454 GSEventRunModal + 168
27 UIKitCore 0x000000019a591274 96636F64-106F-30C8-A780-82DCEBB0F443 + 1266292
28 UIKitCore 0x000000019a55ca28 UIApplicationMain + 336
29 UBScoring 0x00000001049601f4 xamarin_UIApplicationMain + 60
30 UBScoring 0x0000000104b33324 do_icall + 316
31 UBScoring 0x0000000104b318f4 do_icall_wrapper + 348
32 UBScoring 0x0000000104b24e28 mono_interp_exec_method + 2580
33 UBScoring 0x0000000104b229e0 interp_runtime_invoke + 236
34 UBScoring 0x0000000104af11a8 mono_jit_runtime_invoke + 1244
35 UBScoring 0x0000000104a9891c mono_runtime_invoke_checked + 148
36 UBScoring 0x0000000104a9e820 mono_runtime_exec_main_checked + 116
37 UBScoring 0x0000000104af7be4 mono_jit_exec + 356
38 UBScoring 0x00000001049760ac xamarin_main + 2032
39 UBScoring 0x0000000104b64634 important + 64
40 dyld 0x00000001bea53f08 86D5253D-4FD1-36F3-B4AB-25982C90CBF4 + 257800
Code
The CollectionView within the web page’s structure
The code when the ViewModel is reacting to the message
[ObservableProperty] public partial ObservableRangeCollection SessionLog { get; set; } = new();
public void RegisterLogging()
{
WeakReferenceMessenger.Default.Register(this, (r, m) => MainThread.BeginInvokeOnMainThread(() =>
{
SessionLog.Add($"{DateTime.Now:HH:mm:ss} | {m.Worth}");
}));
}
public class UserLogMessage(string message) : ValueChangedMessage(message)
{
public UserLogMessage(string CompetitionName, LoadCompetitionStatus standing) : this(StatusToMessage(CompetitionName, standing)) { }
non-public static string StatusToMessage(string CompetitionName, LoadCompetitionStatus standing)
{
return $"{CompetitionName} - {standing}";
}
}
The operate referred to as when clicking on the Button inflicting the crash
[RelayCommand]
public void ReloadCompetitionInfo()
{
MainThread.BeginInvokeOnMainThread(async () =>
{
IsBusy = true;
IsSyncing = true;
count_i = 0;
await AppCore.Occasion.ReloadCompetitionInfo();
AppData.Occasion.WriteLogFile("Competitors reloaded from server.");
CanBroadcast = AppData.Occasion.AppDataCompetitions.LoggedOnUser.CanBroadcast;
Broadcasting = AppData.Occasion.AppDataSettings.Broadcast;
IsSyncing = false;
IsBusy = false;
});
}
The LoadCompetitionFromApiResponse, referred to as from inside ReloadCompetitionInfo
non-public static UBModels.Competitors LoadCompetitionFromApiResponse(UBApiModels.CompetitionData CompetitionDataFromUBAPI, bool IsMatchDirector)
{
UBModels.Competitors AppCompetition = new();
WeakReferenceMessenger.Default.Ship(new UserLogMessage(CompetitionName: AppCompetition.Title, LoadCompetitionStatus.Init));
// Each Load[...]FromUBAPI technique ends with a brand new UserLogMessage being despatched
if (CompetitionDataFromUBAPI.squads.Depend != 0) LoadSquadsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.groups.Depend != 0) LoadTeamsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.opponents.Depend != 0) LoadCompetitorsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.attracts.Depend != 0) LoadBracketsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.rounds.Depend != 0) LoadRoundsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.targets.Depend != 0) LoadTargetsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.contest_results.Depend != 0) LoadResultsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
if (CompetitionDataFromUBAPI.duels.Depend != 0) LoadDuelsFromApiResponse(AppCompetition, CompetitionDataFromUBAPI);
WeakReferenceMessenger.Default.Ship(new UserLogMessage(AppCompetition.Title, LoadCompetitionStatus.CompetitionLoaded));
return AppCompetition;
}
Workaround
I truly discovered a possible workaround : each time I ship a message by means of the messenger in ReloadCompetitionInfo
, I added a name to a brand new technique WaitIOS
earlier than. Nevertheless it feels prefer it’s not the proper strategy, and that I should not want so as to add a delay to each single message in right here.
non-public static void WaitiOS(int delayMs = 1000)
{
#if IOS
Job.Delay(delayMs).Wait();
#endif
}