Как разорвать ссылочный цикл между контроллером представления и источником данных
Рассмотрим этот простой пример:
public partial class TableViewController : UITableViewController
{
public TableViewController (IntPtr handle) : base (handle)
{
}
protected override void Dispose (bool disposing)
{
Console.WriteLine (String.Format ("{0} controller disposed - {1}", this.GetType (), this.GetHashCode ()));
base.Dispose (disposing);
}
public override void ViewDidLoad ()
{
//TableView.Source = new TableSource(this);
TableView.Source = new TableSource();
}
}
public class TableSource : UITableViewSource {
private TableViewController controller;
string CellIdentifier = "TableCell";
public TableSource ()
{
}
public TableSource (TableViewController controller)
{
this.controller = controller;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
return 1;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
//if there are no cells to reuse, create a new one
if (cell == null){
cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier);
}
cell.TextLabel.Text = "test";
return cell;
}
}
Я заметил, что контроллер представления (TableViewController) никогда не выпускается. Контроллер табличного представления имеет ссылку на источник данных, но источник данных также имеет ссылку на контроллер табличного представления.
С TableView.Source = new TableSource();
контроллер представления освобождается, с TableView.Source = new TableSource(this);
это не.
Как этот ссылочный цикл должен быть разорван, чтобы все освободилось?
Редактировать:
Теперь я попробовал WeakReference
:
С помощью WeakReference
Dispose
Метод вызывается, когда контроллер представления выталкивается из стека навигации.
В ViewDidLoad
:
TableView.Source = new TableSource(new WeakReference<TableViewController> (this));
В источнике данных:
private WeakReference<TableViewController> controller;
public TableSource (WeakReference<TableViewController> controller)
{
this.controller = controller;
}
Я встроил это в свой реальный проект, но как я могу получить доступ к своему контроллеру? Я получаю сообщение
Тип "System.WeakReference" не содержит определения для "xxx", и метод расширения "xxx" типа "System.WeakReference" не найден. Вам не хватает ссылки на сборку?
3 ответа
Вы работаете с Xamarin, как я вижу? Вы пробовали WeakReference? https://msdn.microsoft.com/en-us/library/system.weakreference(v=vs.110).aspx
PS:
private WeakReference weakController;
установить:
this.weakController = new WeakReference(controller);
получить:
if (weakController.isAlive)
{
TableViewController controller = weakController.Target as TableViewController;
}
Менять
public partial class TableViewController : UITableViewController
в
public partial class TableViewController : UITableViewController, UITableViewSource
а во ViewDidLoad просто делай
self.TableView.Source = self;
свойство source уже является слабой внутренней ссылкой, поэтому у вас нет проблем с этим. Это удобное свойство, чтобы сделать tbaleviewcontroller делегатом и источником данных в целом. (Как и в родной iOS)
Вы можете переместить методы в сам контроллер, что будет меньше хлопот, чем WeakReference. Затем пометьте их атрибутом экспорта, который затем позволяет установить свойство UITableView.WeakDataSource для самого контроллера.
[Export("tableView:numberOfRowsInSection:")]
public nint RowsInSection (UITableView tableview, nint section)
[Export("tableView:cellForRowAtIndexPath:")]
public UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
После их перемещения вы можете прикрепить источник данных:
public override void ViewDidLoad ()
{
TableView.WeakDataSource = this;
}