我想向人们保证,我已经阅读了互联网上解释使用按钮从堆栈中弹出 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/