Проблема в том, что вы держите строгую ссылку на экземпляр NSURLSession
в своем объекте NSURLSessionDelegate
и никогда не отменяете сеанс. Согласно Документация Apple
Объект сеанса сохраняет строгую ссылку на этот делегат до тех пор, пока ваше приложение не закроет или явно не сделает недействительным сеанс. Если вы не аннулируете сеанс, ваше приложение будет терять память до тех пор, пока оно не выйдет.
Вы должны сделать недействительным сеанс в какой-то момент. Также похоже, что вы создаете сильный ссылочный цикл здесь:
WAReportController
имеет сильную ссылку на NSUrlSession
; NSURLSession
имеет сильную ссылку на ReportDownloadDelegate
; и ReportDownloadDelegate
имеет сильную ссылку на WAReportController
;. Вы видите проблему здесь?
Вы должны использовать слабые ссылки везде, где это возможно. Попробуйте что-то вроде этого:
public class ReportDownloadDelegate : NSUrlSessionDownloadDelegate
{
private WeakReference<WAReportController> _vc;
public ReportDownloadDelegate(WAReportController vc)
{
_vc = vc;
}
public override void DidWriteData(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)
{
if (_vc != null) {
float progress = totalBytesWritten / (float)totalBytesExpectedToWrite;
Console.WriteLine(string.Format("progress: {0}", progress));
DispatchQueue.MainQueue.DispatchAsync(() => {
_vc.UpdateDownloadProgress(progress); // updates successfully only the first time
});
}
}
public override void DidFinishDownloading(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, NSUrl location)
{
if (_vc != null) {
_vc.DismissDownloadProgressAlert();
}
}
}
и, по вашему мнению, класс контроллера:
public void DismissDownloadProgressAlert()
{
if (downloadProgressAlert != null) {
InvokeOnMainThread(() => {
downloadProgressAlert.DismissViewController(false, null);
});
}
session.InvalidateAndCancel() // I didn't type in an IDE so not sure if this is the exact method signature.
session = null;
}
Таким образом, как только задача загрузки будет завершена, и вы отклоните предупреждение о прогрессе и аннулируете сеанс. NSURLSession
, в свою очередь, выпустит WAReportController
экземпляр. Теперь не обязательно делать недействительной сессию в методе DismissDownloadProgressAlert()
. Но вы должны сделать недействительным сеанс , когда вы закончите использовать сеанс. Это может быть когда вы увольняете свой контроллер вида или когда считаете нужным. Я просто привел это здесь в качестве примера.
Теперь все это основано на документации Apple и моих знаниях по управлению памятью на iOS. Я никогда не работал над Xamarin и, возможно, ошибаюсь из-за того, что используются слабые ссылки по сравнению с нативной разработкой для iOS. Надеюсь, это поможет!