Как разорвать ссылочный цикл между контроллером представления и источником данных

Рассмотрим этот простой пример:

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;
}
Другие вопросы по тегам