dotnet / dotnet/maui

Infinite Measure Looping on iOS (we missed at lest one)

Open
#37,892 1 comment 1 reaction 0 assignees View on GitHub
area-layout i/regression partner/syncfusion platform/ios regressed-in-10-preview1 s/triaged s/verified t/bug
Dominant language
C#
Stars
23.3k
Forks
2k
Avg merge
1d 15h
Merged PRs (30d)
290

Description

### Description

Earlier this year i reported #34042 - it was fixed.

I have now found another one of those Infinite looping bugs, one we initial missed.

I have updated the sample repo with a new example and updated the maui nuget version to 10.0.100.

Note that i ran the issue on a iOS simulator (iPhone 16 Pro - iOS 18.6). The issue is not limited to this device. We have seen the bug/issue on devices with iOS version 18 and 26. More on 18 than 26, and what fails on one model does not on another.

Due to the "randomness" of this error we have decided to implement a circuit breaker in the ViewHandler.ViewMapper. We have added a MeasureCounter attached property and subscribe to the SizeChangedEvent and set View.HeightRequest to the View.Height if the MeasureCounter is > 100 iterations. 🤮

For Example 4 i have extracted the failing code and removed parts that did not contribute to the looping. If you want i can provide more examples/samples. Please do not hesitate

### Steps to Reproduce

pull the code from the repo, run the code on iOS simulator (iPhone 16 Pro - iOS 18.6).
press "Example 4" and wait for the quick and dirty loop detector to stop the loop (stopping after 500 size changed)
The app is unresponsive while the loop is running.

### Link to public reproduction project repository

https://github.com/JohnTraDolta/MauiInfiniteMeasureLoopingBug

### Version with bug

10.0.100

### Is this a regression from previous behavior?

Yes, this used to work in .NET MAUI

### Last version that worked well

9.0.120 SR12

### Affected platforms

iOS

### Affected platform versions

iOS 18 and 26.

### Did you find any workaround?

Yes here it is
```
ViewHandler.ViewMapper.AppendToMapping("MeasureCounterFallbackHandler", (handler, iView) =>
{
if (iView is View view)
{
view.SizeChanged += ViewOnSizeChanged;
view.Unloaded += ViewOnUnloaded;

void ViewOnUnloaded(object? sender, EventArgs e)
{
if (sender is not View v)
return;

(sender as View).Unloaded -= ViewOnUnloaded;
v.SizeChanged -= ViewOnSizeChanged;
}

void ViewOnSizeChanged(object? sender, EventArgs e)
{
if (MeasureCounter.IsGreaterThanX(view, 100))
{
view.HeightRequest = view.Height;
return;
}

MeasureCounter.IncrementCount(view);
Debug.WriteLine($"[MeasureCounter:] {MeasureCounter.GetCount(view)}");
}
}
});
```
```
public class MeasureCounter
{

public static readonly BindableProperty CountProperty = BindableProperty.CreateAttached("Count", typeof(int), typeof(MeasureCounter), 0);
public static int GetCount(BindableObject bindable) => (int)bindable.GetValue(CountProperty);
public static void SetCount(BindableObject bindable, int value) => bindable.SetValue(CountProperty, value);

public static void IncrementCount(BindableObject bindable) => SetCount(bindable, GetCount(bindable) + 1);
public static bool IsGreaterThanX(BindableObject bindable, int x) => GetCount(bindable) > x;
}
```

### Relevant log output

```shell

```

Contributor guide

Open the contributing guide

Research direction

Start with the linked MauiInfiniteMeasureLoopingBug repository and run Example 4 on the specified iOS simulator to reproduce the measure loop. Then trace the relevant ViewHandler.ViewMapper and SizeChanged behavior; done means Example 4 no longer makes the app unresponsive or requires the loop detector to stop it.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, ios
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.