Skip to content

[iOS] Fix HEIC images picked via PickPhotosAsync not displayed#34954

Merged
kubaflo merged 1 commit into
dotnet:inflight/currentfrom
HarishwaranVijayakumar:fix-34786
Apr 15, 2026
Merged

[iOS] Fix HEIC images picked via PickPhotosAsync not displayed#34954
kubaflo merged 1 commit into
dotnet:inflight/currentfrom
HarishwaranVijayakumar:fix-34786

Conversation

@HarishwaranVijayakumar
Copy link
Copy Markdown
Contributor

@HarishwaranVijayakumar HarishwaranVijayakumar commented Apr 14, 2026

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Issue Details

  • HEIC images picked via PickPhotosAsync are not displayed — the image appears blank, whereas other image formats (e.g., JPEG, PNG) display correctly.

Root Cause of the issue

  • PR 34250 moved CompletedHandler invocation into the DismissViewController completion callback. This introduced a GC race condition where PhotoPickerPresentationControllerDelegate.Dispose() fires tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC transcoding.
  • HEIC is particularly affected because NSItemProvider.LoadDataRepresentationAsync transcoding is significantly slower than JPEG/PNG loading, widening the GC window.

Description of Change

Race condition prevention:

  • In PhotoPickerDelegate.DidFinishPicking, the Handler property of PhotoPickerPresentationControllerDelegate is set to null before dismissing the picker to avoid a garbage collection race condition that could interfere with the async completion handler, especially during slow operations like HEIC transcoding.

Issues Fixed

Fixes #34953

Tested the behaviour in the following platforms

  • - Windows
  • - Android
  • - iOS
  • - Mac
Before After
Before_.34786.mov
After_.34786.mov

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Apr 14, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Hey there @@HarishwaranVijayakumar! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 15, 2026

🚦 Gate — Test Before and After Fix

👋 @HarishwaranVijayakumar — new gate results are available. Please review the latest session below.

🚦 Gate Session45a573b · Add fix · 2026-04-15 10:25 UTC

Gate Result: ⚠️ SKIPPED

No tests were detected in this PR.

Recommendation: Add tests to verify the fix using the write-tests-agent:

@copilot write tests for this PR

The agent will analyze the issue, determine the appropriate test type (UI test, device test, unit test, or XAML test), and create tests that verify the fix.


@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 15, 2026

🤖 AI Summary

👋 @HarishwaranVijayakumar — new AI review results are available. Please review the latest session below.

📊 Review Session45a573b · Add fix · 2026-04-15 10:50 UTC
🔍 Pre-Flight — Context & Validation

Issue: #34953 - [iOS] [Regression] HEIC images picked via PickPhotosAsync not displayed
PR: #34954 - [iOS] Fix HEIC images picked via PickPhotosAsync not displayed
Platforms Affected: iOS only
Files Changed: 1 implementation (src/Essentials/src/MediaPicker/MediaPicker.ios.cs), 0 test

Key Findings

  • Regression introduced by PR [iOS] Fix: invoke MediaPicker completion handler after DismissViewController #34250 which moved CompletedHandler invocation into the DismissViewController completion callback
  • PhotoPickerPresentationControllerDelegate has a Handler property set to () => tcs.TrySetResult([]) (line 237) — meant for user-swipe-cancel scenarios
  • Both DidDismiss and Dispose on PhotoPickerPresentationControllerDelegate invoke Handler
  • GC can collect PhotoPickerPresentationControllerDelegate and fire DisposeHandler?.Invoke()tcs.TrySetResult([]) BEFORE the async CompletedHandler finishes HEIC transcoding (LoadDataRepresentationAsync is slow for HEIC)
  • HEIC transcoding is significantly slower than JPEG/PNG, widening the GC race window
  • Fix: null out pd.Handler in DidFinishPicking before calling DismissViewController, so that when Dispose fires it cannot call TrySetResult([]) prematurely
  • Issue is milestoned to .NET 10 SR7 and labeled regressed-in-inflight/current
  • No tests added; Gate result: ⚠️ SKIPPED (no tests detected)

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34954 Null out pd.Handler before DismissViewController in DidFinishPicking ⚠️ SKIPPED (no tests in PR) MediaPicker.ios.cs Original PR

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (opus-4.6) Remove Handler?.Invoke() from PhotoPickerPresentationControllerDelegate.Dispose() entirely ⚠️ BLOCKED (compiles; no device) MediaPicker.ios.cs Relies solely on DidDismiss for swipe-cancel; may lose safety net
2 try-fix (sonnet-4.6) Add _pickerCompleted flag + MarkCompleted() to delegate; gate Handler?.Invoke() in both DidDismiss and Dispose ⚠️ BLOCKED (compiles; no device) MediaPicker.ios.cs Explicit state; encapsulates cancel-vs-complete within delegate; more verbose
3 try-fix (gpt-5.3-codex) Hold strong reference to PhotoPickerPresentationControllerDelegate on PhotoPickerDelegate to prevent premature GC ❌ FAIL (MSB3644 build env blocker) MediaPicker.ios.cs Prevents GC race by extending lifetime; build env blocked runtime test
4 try-fix (gpt-5.4) Interlocked.Exchange atomic one-shot callback consumption ⚠️ BLOCKED (MSB3644 build env) MediaPicker.ios.cs Thread-safe but more complex than needed (iOS main-thread only)
PR PR #34954 Null pd.Handler in DidFinishPicking before DismissViewController ⚠️ SKIPPED (Gate; no tests) MediaPicker.ios.cs Original PR; minimal, targeted, preserves cancel safety net

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 No NO NEW IDEAS — all approaches target same fundamental race

Exhausted: Yes (4/4 models, 1 cross-pollination round)
Selected Fix: PR's fix — null pd.Handler before DismissViewController — smallest, most targeted, preserves swipe-cancel safety net, no additional complexity


📋 Report — Final Recommendation

✅ Final Recommendation: APPROVE

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE Issue #34953 — iOS regression in PickPhotosAsync for HEIC images
Gate ⚠️ SKIPPED No tests in PR — recommend author adds tests
Try-Fix ✅ COMPLETE 4 attempts, 0 PASS (all BLOCKED by env / no iOS device); PR's fix selected as best
Report ✅ COMPLETE

Summary

PR #34954 fixes a GC race condition in MediaPicker.ios.cs that causes HEIC images picked via PickPhotosAsync to return blank. The fix is minimal, correctly targeted, and well-commented. All 4 alternative approaches explored via try-fix were either more complex or equivalent — none outperformed the PR's one-liner. Gate was SKIPPED because no tests were added; recommending tests via write-tests-agent.

Root Cause

PhotoPickerPresentationControllerDelegate.Dispose() invokes Handler?.Invoke()tcs.TrySetResult([]) (empty list). This fires during GC after DismissViewController is called but before the async CompletedHandler finishes HEIC transcoding via NSItemProvider.LoadDataRepresentationAsync. HEIC is particularly vulnerable because transcoding is significantly slower than JPEG/PNG, widening the GC collection window.

Regression introduced by PR #34250 which moved CompletedHandler invocation into the DismissViewController completion callback.

Fix Quality

The fix is correct and minimal:

  • Nulls pd.Handler in DidFinishPicking before DismissViewController — prevents the race at the exact right moment
  • Preserves the swipe-cancel behavior: DidDismiss still fires Handler when user swipes down (the _pickerCompleted path is unaffected)
  • Well-commented explaining the race condition

Minor observation (non-blocking): The single-photo PickPhotoAsync path (line ~133–162) has the same PhotoPickerPresentationControllerDelegate pattern. However, its CompletedHandler calls GetFileResult (synchronous), so the race window is much smaller. Out of scope for this PR.

Missing tests: Gate flagged no tests added. A device test verifying HEIC photo pick results is recommended.


@MauiBot MauiBot added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Apr 15, 2026
@kubaflo kubaflo merged commit 66622d1 into dotnet:inflight/current Apr 15, 2026
5 of 12 checks passed
devanathan-vaithiyanathan pushed a commit to Tamilarasan-Paranthaman/maui that referenced this pull request Apr 21, 2026
…t#34954)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details

- HEIC images picked via PickPhotosAsync are not displayed — the image
appears blank, whereas other image formats (e.g., JPEG, PNG) display
correctly.

### Root Cause of the issue

- PR [34250](dotnet#34250) moved
CompletedHandler invocation into the DismissViewController completion
callback. This introduced a GC race condition where
PhotoPickerPresentationControllerDelegate.Dispose() fires
tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC
transcoding.
- HEIC is particularly affected because
NSItemProvider.LoadDataRepresentationAsync transcoding is significantly
slower than JPEG/PNG loading, widening the GC window.

### Description of Change
**Race condition prevention:**

* In `PhotoPickerDelegate.DidFinishPicking`, the `Handler` property of
`PhotoPickerPresentationControllerDelegate` is set to `null` before
dismissing the picker to avoid a garbage collection race condition that
could interfere with the async completion handler, especially during
slow operations like HEIC transcoding.
<!-- Enter description of the fix in this section -->

### Issues Fixed
Fixes dotnet#34953

### Tested the behaviour in the following platforms

- [ ] - Windows 
- [ ] - Android
- [x] - iOS
- [ ] - Mac

| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/368192e4-57ea-4732-82df-3e3ca386ab35">
| <video
src="https://github.com/user-attachments/assets/0e3a5066-e092-4461-9199-1730475307d8">
|

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
PureWeen pushed a commit that referenced this pull request Apr 22, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details

- HEIC images picked via PickPhotosAsync are not displayed — the image
appears blank, whereas other image formats (e.g., JPEG, PNG) display
correctly.

### Root Cause of the issue

- PR [34250](#34250) moved
CompletedHandler invocation into the DismissViewController completion
callback. This introduced a GC race condition where
PhotoPickerPresentationControllerDelegate.Dispose() fires
tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC
transcoding.
- HEIC is particularly affected because
NSItemProvider.LoadDataRepresentationAsync transcoding is significantly
slower than JPEG/PNG loading, widening the GC window.

### Description of Change
**Race condition prevention:**

* In `PhotoPickerDelegate.DidFinishPicking`, the `Handler` property of
`PhotoPickerPresentationControllerDelegate` is set to `null` before
dismissing the picker to avoid a garbage collection race condition that
could interfere with the async completion handler, especially during
slow operations like HEIC transcoding.
<!-- Enter description of the fix in this section -->

### Issues Fixed
Fixes #34953

### Tested the behaviour in the following platforms

- [ ] - Windows 
- [ ] - Android
- [x] - iOS
- [ ] - Mac

| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/368192e4-57ea-4732-82df-3e3ca386ab35">
| <video
src="https://github.com/user-attachments/assets/0e3a5066-e092-4461-9199-1730475307d8">
|

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
PureWeen pushed a commit that referenced this pull request Apr 28, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details

- HEIC images picked via PickPhotosAsync are not displayed — the image
appears blank, whereas other image formats (e.g., JPEG, PNG) display
correctly.

### Root Cause of the issue

- PR [34250](#34250) moved
CompletedHandler invocation into the DismissViewController completion
callback. This introduced a GC race condition where
PhotoPickerPresentationControllerDelegate.Dispose() fires
tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC
transcoding.
- HEIC is particularly affected because
NSItemProvider.LoadDataRepresentationAsync transcoding is significantly
slower than JPEG/PNG loading, widening the GC window.

### Description of Change
**Race condition prevention:**

* In `PhotoPickerDelegate.DidFinishPicking`, the `Handler` property of
`PhotoPickerPresentationControllerDelegate` is set to `null` before
dismissing the picker to avoid a garbage collection race condition that
could interfere with the async completion handler, especially during
slow operations like HEIC transcoding.
<!-- Enter description of the fix in this section -->

### Issues Fixed
Fixes #34953

### Tested the behaviour in the following platforms

- [ ] - Windows 
- [ ] - Android
- [x] - iOS
- [ ] - Mac

| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/368192e4-57ea-4732-82df-3e3ca386ab35">
| <video
src="https://github.com/user-attachments/assets/0e3a5066-e092-4461-9199-1730475307d8">
|

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
PureWeen pushed a commit that referenced this pull request Apr 29, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details

- HEIC images picked via PickPhotosAsync are not displayed — the image
appears blank, whereas other image formats (e.g., JPEG, PNG) display
correctly.

### Root Cause of the issue

- PR [34250](#34250) moved
CompletedHandler invocation into the DismissViewController completion
callback. This introduced a GC race condition where
PhotoPickerPresentationControllerDelegate.Dispose() fires
tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC
transcoding.
- HEIC is particularly affected because
NSItemProvider.LoadDataRepresentationAsync transcoding is significantly
slower than JPEG/PNG loading, widening the GC window.

### Description of Change
**Race condition prevention:**

* In `PhotoPickerDelegate.DidFinishPicking`, the `Handler` property of
`PhotoPickerPresentationControllerDelegate` is set to `null` before
dismissing the picker to avoid a garbage collection race condition that
could interfere with the async completion handler, especially during
slow operations like HEIC transcoding.
<!-- Enter description of the fix in this section -->

### Issues Fixed
Fixes #34953

### Tested the behaviour in the following platforms

- [ ] - Windows 
- [ ] - Android
- [x] - iOS
- [ ] - Mac

| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/368192e4-57ea-4732-82df-3e3ca386ab35">
| <video
src="https://github.com/user-attachments/assets/0e3a5066-e092-4461-9199-1730475307d8">
|

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
github-actions Bot pushed a commit that referenced this pull request May 6, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!
<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Issue Details

- HEIC images picked via PickPhotosAsync are not displayed — the image
appears blank, whereas other image formats (e.g., JPEG, PNG) display
correctly.

### Root Cause of the issue

- PR [34250](#34250) moved
CompletedHandler invocation into the DismissViewController completion
callback. This introduced a GC race condition where
PhotoPickerPresentationControllerDelegate.Dispose() fires
tcs.TrySetResult([]) before the async CompletedHandler finishes HEIC
transcoding.
- HEIC is particularly affected because
NSItemProvider.LoadDataRepresentationAsync transcoding is significantly
slower than JPEG/PNG loading, widening the GC window.

### Description of Change
**Race condition prevention:**

* In `PhotoPickerDelegate.DidFinishPicking`, the `Handler` property of
`PhotoPickerPresentationControllerDelegate` is set to `null` before
dismissing the picker to avoid a garbage collection race condition that
could interfere with the async completion handler, especially during
slow operations like HEIC transcoding.
<!-- Enter description of the fix in this section -->

### Issues Fixed
Fixes #34953

### Tested the behaviour in the following platforms

- [ ] - Windows 
- [ ] - Android
- [x] - iOS
- [ ] - Mac

| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/368192e4-57ea-4732-82df-3e3ca386ab35">
| <video
src="https://github.com/user-attachments/assets/0e3a5066-e092-4461-9199-1730475307d8">
|

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
@github-actions github-actions Bot locked and limited conversation to collaborators May 16, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-essentials-mediapicker community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants