ios - 从 Xamarin.iOS 中的导航堆栈弹出后,ViewController 未被释放

标签 ios xamarin xamarin.ios mono

我想向人们保证,我已经阅读了互联网上解释使用按钮从堆栈中弹出 Controller 时发生内存泄漏的所有文章,并且我知道 UIButton 在使用 Lambdas 触发事件时创建的强引用。

我已经尝试了所有似乎都不适合我的方法。

问题陈述

我有一个 UICollectionViewController 作为根 ViewController 和它上面的一个 float 按钮,我以编程方式创建并添加为 subview 。

这些按钮将 View Controller 插入堆栈。

这是我推送 Controller 的方法。

private void HandleClick(object sender, EventArgs e) {

    var button = sender as UIButton;
    var board = UIStoryboard.FromName("Main", NSBundle.MainBundle);
    switch (button.Tag) { 

        case 3: { 
                var vc = board.InstantiateViewController("BibleViewController");
                this.NavigationController.PushViewController(vc, true);
                vc = null;

                break;

            }
        case 5: { 
                var vc = board.InstantiateViewController("RecordingViewController");
                this.NavigationController.PushViewController(vc, true);
                vc = null;

                break;
            }
        case 7: {  
                var vc = board.InstantiateViewController("CameraFbController");
                this.NavigationController.PushViewController(vc, true);
                vc = null;

                break;
            }
        case 6: {
                var vc = board.InstantiateViewController("NewEmojiController");
                this.NavigationController.PushViewController(vc, true);
                vc = null;

                break;
            }
        case 4: { 
                var vc = board.InstantiateViewController("WriteNShareController");
                this.NavigationController.PushViewController(vc, true);
                vc = null;
                break;
            }
        default : {
                break;
            }



    }
}

假设我正在推送 BibleViewController(案例 3:)

请找到这个 Controller 的代码

public partial class BibleHomeController : UIViewController
{
    IList<string> items;
    IList<string> item1;

    public BibleHomeController() : base("BibleHomeController", null)
    {
    }
    public BibleHomeController(IntPtr handle) : base (handle)
    {
    }
    ~BibleHomeController() { 

        Console.WriteLine("it was called ");

    }
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
    }
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        LoadJson();

        tableView.DataSource = new BTableViewDataSource(items);
        tableView.Delegate = new TableDelegate(items,this);
        tableView.RegisterNibForCellReuse(UINib.FromName("BookCell",NSBundle.MainBundle),BookCell.Key);




    }
    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
        backBtn.TouchUpInside += HandleBackClick;
        nwBtn.TouchUpInside += newBtn;
        oldBtn.TouchUpInside += oldBtnHanle;
    }
    private void HandleBackClick(object sender, EventArgs e)
    {

        this.NavigationController.PopViewController(true);
    }
    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);
        backBtn.TouchUpInside -= HandleBackClick;
        nwBtn.TouchUpInside -= newBtn;
        oldBtn.TouchUpInside -= oldBtnHanle;
                    backBtn = null;
        nwBtn = null;
        oldBtn = null;
        tableView = null;

    }
    private void newBtn(object sender, EventArgs e)
    {

        tableView.DataSource = new BTableViewDataSource(item1);
        tableView.Delegate = new TableDelegate(item1,this);
        tableView.ReloadData();
    }
    private void oldBtnHanle(object sender, EventArgs e)
    {

        tableView.DataSource = new BTableViewDataSource(items);
        tableView.Delegate = new TableDelegate(items,this);
        tableView.ReloadData();
    }
    public override void DidReceiveMemoryWarning()
    {
        base.DidReceiveMemoryWarning();
        // Release any cached data, images, etc that aren't in use.
    }
    private void LoadJson() {
        using (StreamReader r = new StreamReader("BibleSection/BibleBooks/Books.json")) {
            string json = r.ReadToEnd();
            items = JsonConvert.DeserializeObject<List<string>>(json);
        }
        using (StreamReader r = new StreamReader("BibleSection/BibleBooks/NewBook.json"))
        {
            string json = r.ReadToEnd();
            item1 = JsonConvert.DeserializeObject<List<string>>(json);
        }
    }

}
public class BTableViewDataSource : UITableViewDataSource
{
    IList<string> data;

    public BTableViewDataSource(IList<string> list) {

        data = list;
    }
    ~BTableViewDataSource() {
        Console.WriteLine("it was called ");
    }
    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    {
        // if cell is not available in reuse pool, iOS will create one automatically
        // no need to do null check and create cell manually
        var cell = (BookCell)tableView.DequeueReusableCell("BookCell", indexPath) as BookCell;
        cell.PopulateCell(data[indexPath.Row], "");
        cell.SetNeedsLayout();

        //cell.SeparatorInset = UIEdgeInsets.Zero;
            return cell;

    }

    public override nint RowsInSection(UITableView tableView, nint section)
    {

        return data.Count;

    }


}
public class TableDelegate : UITableViewDelegate { 
    IList<string> data;
    BibleHomeController owner;
    public TableDelegate(IList<string> list, BibleHomeController reference)
    {
        owner = reference;
        data = list;
    }
    ~TableDelegate()
    {
    Console.WriteLine("it was called ");
    }
    public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        //base.RowSelected(tableView, indexPath);
        var board = UIStoryboard.FromName("Main", NSBundle.MainBundle);
        var vc = (BibleChapterCollectionview)board.InstantiateViewController("BibleChapterCollectionview") as BibleChapterCollectionview;
        vc.itemName = data[indexPath.Row];
        owner.NavigationController.PushViewController(vc, true);

    }

}

我的问题是,当我在 BibleViewController 中弹出 Controller 时, 没有调用任何类的析构函数,也没有调用 dispose,因此不释放 Controller 内存。

所以每次我推送和弹出时,我都会向堆中添加一些内存。

我想指出,我正在从 viewDidDisappear 方法中的按钮分离所有事件处理程序。

你能帮我看看当我弹出 Controller 时如何释放资源吗?

编辑: 我认为问题出在 tableview.delegate 和 table.datasource 行上。 如果我评论他们,问题就解决了。

我应该使用 weakDelegate 吗?

最佳答案

修改这部分代码对我有用。

private void HandleBackClick(object sender, EventArgs e)
    {
            tableView.Delegate = null;
            tableView.DataSource = null;
            tableView.Source = null;
        this.NavigationController.PopViewController(true);
    }

//下面的修改与问题陈述无关,但需要,因为按钮不需要为空

 public override void ViewWillDisappear(bool animated)
{
    base.ViewWillDisappear(animated);
    backBtn.TouchUpInside -= HandleBackClick;
    nwBtn.TouchUpInside -= newBtn;
    oldBtn.TouchUpInside -= oldBtnHanle;


}

关于ios - 从 Xamarin.iOS 中的导航堆栈弹出后,ViewController 未被释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43964802/

相关文章:

ios - 如何在 Alamofire 4 和 Swift 3 中使用代理服务器

xamarin.forms - 错误 : Failed to resolve "AuthenticationServices.ASWebAuthenticationSession" reference from "Xamarin. iOS

multithreading - 检测您何时进入/离开 Xamarin.iOS 中的主线程

c# - 在代码隐藏中使用数据绑定(bind)

c# - Xamarin UITableView 行在行选择上展开 - 可能的 iOS?

iOS 8 GM 不更新对 Collection View 的约束

ios - 如何判断给定文件是否可以通过照片框架添加到照片库?

ios - 在获取等于 @"unapproved"之类的字符串的 json 响应时显示一个按钮

android - 使用 Xamarin 扩充绑定(bind)库时出现 ClassNotFoundException

c# - XamarinBuildAndroidAarProguardConfigs 任务意外失败