Skip to content

Commit 07be3c6

Browse files
Fixes disposal of temporary file on iOS
Ensures temporary directory used by the file picker is always removed after the file selection is made, regardless of success or failure. Also improves error handling when a view controller cannot be retrieved. Fixes CommunityToolkit#2460
1 parent 47ddfe5 commit 07be3c6

File tree

1 file changed

+26
-31
lines changed

1 file changed

+26
-31
lines changed

src/CommunityToolkit.Maui.Core/Essentials/FileSaver/FileSaverImplementation.macios.cs

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ public sealed partial class FileSaverImplementation : IFileSaver, IDisposable
1010
{
1111
UIDocumentPickerViewController? documentPickerViewController;
1212
TaskCompletionSource<string>? taskCompetedSource;
13-
NSUrl? tempDirectoryPath;
1413

1514
/// <inheritdoc />
1615
public void Dispose()
@@ -22,38 +21,45 @@ async Task<string> InternalSaveAsync(string initialPath, string fileName, Stream
2221
{
2322
cancellationToken.ThrowIfCancellationRequested();
2423
var fileManager = NSFileManager.DefaultManager;
25-
tempDirectoryPath = fileManager.GetTemporaryDirectory().Append(Guid.NewGuid().ToString(), true);
24+
var tempDirectoryPath = fileManager.GetTemporaryDirectory().Append(Guid.NewGuid().ToString(), true);
2625
var isDirectoryCreated = fileManager.CreateDirectory(tempDirectoryPath, true, null, out var error);
2726
if (!isDirectoryCreated)
2827
{
2928
throw new FileSaveException(error?.LocalizedDescription ?? "Unable to create temp directory.");
3029
}
3130

3231
var fileUrl = tempDirectoryPath.Append(fileName, false);
33-
await WriteStream(stream, fileUrl.Path ?? throw new Exception("Path cannot be null."), progress, cancellationToken);
32+
try
33+
{
34+
await WriteStream(stream, fileUrl.Path ?? throw new Exception("Path cannot be null."), progress, cancellationToken);
3435

35-
cancellationToken.ThrowIfCancellationRequested();
36-
taskCompetedSource?.TrySetCanceled(CancellationToken.None);
37-
var tcs = taskCompetedSource = new(cancellationToken);
36+
cancellationToken.ThrowIfCancellationRequested();
37+
taskCompetedSource?.TrySetCanceled(CancellationToken.None);
38+
var tcs = taskCompetedSource = new(cancellationToken);
3839

39-
documentPickerViewController = new([fileUrl], true)
40-
{
41-
DirectoryUrl = NSUrl.FromString(initialPath)
42-
};
43-
documentPickerViewController.DidPickDocumentAtUrls += DocumentPickerViewControllerOnDidPickDocumentAtUrls;
44-
documentPickerViewController.WasCancelled += DocumentPickerViewControllerOnWasCancelled;
40+
documentPickerViewController = new([fileUrl], true)
41+
{
42+
DirectoryUrl = NSUrl.FromString(initialPath)
43+
};
44+
documentPickerViewController.DidPickDocumentAtUrls += DocumentPickerViewControllerOnDidPickDocumentAtUrls;
45+
documentPickerViewController.WasCancelled += DocumentPickerViewControllerOnWasCancelled;
4546

46-
var currentViewController = Platform.GetCurrentUIViewController();
47-
if (currentViewController is not null)
48-
{
49-
currentViewController.PresentViewController(documentPickerViewController, true, null);
47+
var currentViewController = Platform.GetCurrentUIViewController();
48+
if (currentViewController is not null)
49+
{
50+
currentViewController.PresentViewController(documentPickerViewController, true, null);
51+
}
52+
else
53+
{
54+
throw new FileSaveException("Unable to get a window where to present the file saver UI.");
55+
}
56+
57+
return await tcs.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
5058
}
51-
else
59+
finally
5260
{
53-
throw new FileSaveException("Unable to get a window where to present the file saver UI.");
61+
fileManager.Remove(tempDirectoryPath, out _);
5462
}
55-
56-
return await tcs.Task.WaitAsync(cancellationToken).ConfigureAwait(false);
5763
}
5864

5965
Task<string> InternalSaveAsync(string fileName, Stream stream, IProgress<double>? progress, CancellationToken cancellationToken)
@@ -64,7 +70,6 @@ Task<string> InternalSaveAsync(string fileName, Stream stream, IProgress<double>
6470
void DocumentPickerViewControllerOnWasCancelled(object? sender, EventArgs e)
6571
{
6672
taskCompetedSource?.TrySetException(new FileSaveException("Operation cancelled."));
67-
CleanupTempDirectory();
6873
InternalDispose();
6974
}
7075

@@ -76,19 +81,9 @@ void DocumentPickerViewControllerOnDidPickDocumentAtUrls(object? sender, UIDocum
7681
}
7782
finally
7883
{
79-
CleanupTempDirectory();
8084
InternalDispose();
8185
}
8286
}
83-
84-
void CleanupTempDirectory()
85-
{
86-
if (tempDirectoryPath is not null)
87-
{
88-
var fileManager = NSFileManager.DefaultManager;
89-
fileManager.Remove(tempDirectoryPath, out var _);
90-
}
91-
}
9287

9388

9489
void InternalDispose()

0 commit comments

Comments
 (0)