0

UITableViewWaitTableViewという名前のコントローラーがあります。セルは1つだけです。これが、UITableViewCellクラスのコードです。

    public class TableViewWaitCell : UITableViewCell
    {
        public UIActivityIndicatorView activityIndicator = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray);
        public UILabel lblLoading = new UILabel();

        public TableViewWaitCell(UITableViewCellStyle style, string reuseIdentifier) : base (style, reuseIdentifier)
        {
            this.SelectionStyle = UITableViewCellSelectionStyle.None;
        }

        ~TableViewWaitCell(){
            System.Console.WriteLine("TableViewWaitCell.~TableViewWaitCell");
            lblLoading = null;
            activityIndicator = null;   
            System.GC.Collect();
        }
       protected override void Dispose (bool disposing){
            System.Console.WriteLine("TableViewWaitCell.Dispose");
            lblLoading = null;
            activityIndicator = null;
            base.Dispose (disposing);
            GC.Collect();
        }

        public override void Draw (System.Drawing.RectangleF rect)
        {
            base.Draw (rect);

            var context = UIGraphics.GetCurrentContext();
            var gradient = new CGGradient(
            CGColorSpace.CreateDeviceRGB(),
                new float[] { 1f, 1f, 1f, 1f,
                              0.68f, 0.68f, 0.72f, 1f },
                new float[] { 0f, 1f } );
                context.DrawLinearGradient(gradient,
                    new PointF(rect.X+rect.Width/2, rect.Y),
                    new PointF(rect.X+rect.Width/2, rect.Y+rect.Height),
                    CGGradientDrawingOptions.DrawsAfterEndLocation);

            var activityIndicatorViewFrame = new RectangleF(rect.X + rect.Width/2-10, rect.Y+10, 20, 20);
            this.activityIndicator  .Frame = activityIndicatorViewFrame;
            this.activityIndicator.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
            this.activityIndicator.StartAnimating();
            this.AddSubview(this.activityIndicator);

            var labelFrame = new RectangleF(rect.X, rect.Y+10+activityIndicatorViewFrame.Height, rect.Width, 35);
            this.lblLoading.Frame = labelFrame;
            this.lblLoading.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
            this.lblLoading.TextColor = UIColor.Black;
            this.lblLoading.BackgroundColor = UIColor.Clear;
            this.lblLoading.TextAlignment = UITextAlignment.Center;
            this.lblLoading.Text = Dictionary.GetValue("Loading");
            this.AddSubview(this.lblLoading);
        }
    }

ViewWillDisappearこれがメインの方法ですUIViewController

        public override void ViewWillDisappear (bool animated)
    {
        Console.WriteLine("SpotlightView.ViewWillDisappear");
        if(this.PopoverController!=null)
            this.PopoverController.Dismiss(true);
        this.PopoverController = null;
        this.tableView.RemoveFromSuperview();
        this.WaitTableView.RemoveFromSuperview();
        this.searchBar.RemoveFromSuperview();
        this.tableView.Source = null;
        this.tableView.Dispose();
        this.tableView = null;
        this.WaitTableView.Source = null;
        this.WaitTableView.Dispose();
        this.WaitTableView = null;
        this.searchBar.Delegate = null;
        this.searchBar.Dispose();
        this.searchBar = null;

        base.ViewWillDisappear (animated);
    }

私の問題は、デストラクタもDisposeofmycellsも呼び出されなかったことです。ヒープショットを実行すると、TableViewWaitCellクラスのインスタンスの数が増え、アプリ内を移動します。モノタッチで細胞のライフサイクルがどのように管理されているのかわかりませんが、何を間違えたのでしょうか?

4

2 に答える 2

2

共有したコードでこの問題を引き起こすようなものは見当たりません。ただし、セルがどのように構築および保存されているかは示していません。サンプルコードに表示されていないルートによって、オブジェクトが存続している可能性があります。Disposeと呼び出されているファイナライザーを示すサンプルを以下に作成しました。

シミュレーターを使用すると、テーブルビューとセルがすばやく収集されます。通常、「テーブルの表示」ボタンを2回押した後。

デバイスで実行すると、異なる動作が示されます。テーブルとセルはすぐには収集されません。最も簡単な説明は、GCが必要なときにのみ実行されるように「調整」されていることです。そのため、アプリが多くのメモリを使用していない場合、すべてのオブジェクトは引き続き機能します。

サンプルに示されているように、GCを強制的に実行するために実行できることが2つあります。

showTable.TouchUpInside += delegate {
    navController.PushViewController (new MyViewController (), true);
    // Not a great idea to call Collect but you could to force it.
    // GC.Collect ();
};

allocate.TouchUpInside += delegate {
    // Trigger the GC by creating a bunch of objects
    System.Collections.Generic.List<object> list = new System.Collections.Generic.List <object> ();
    for (int i=0; i<2048; i++)
    {
        list.Add (new object ());
    }
};

まず、GC.Collectを呼び出すことができます。ただし、お勧めしません。GCは、必要なときに実行させると最適に実行されます。(ほとんどの場合。) GC.Collectを呼び出すことができるのはいつですか。

次に、コードを書き続けて、GCに最適なものを決定させます。サンプルでは、​​オブジェクトの束を割り当ててリストに追加する別のボタンを追加しました。したがって、テーブルビューとメインビューを数回切り替えてから、割り当てボタンを数回押すと、ファイナライザーが実行されるのがわかります。

using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Drawing;

namespace delete20130320
{
    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        UIWindow window;


        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            window = new UIWindow (UIScreen.MainScreen.Bounds);

            var mainView = new UIViewController ();
            var showTable = UIButton.FromType (UIButtonType.RoundedRect);
            showTable.Frame = new System.Drawing.RectangleF (10, 10, 150, 35);
            showTable.SetTitle ("Show Table", UIControlState.Normal);

            var allocate = UIButton.FromType (UIButtonType.RoundedRect);
            allocate.Frame = new System.Drawing.RectangleF (10, 55, 150, 35);
            allocate.SetTitle ("Allocate", UIControlState.Normal);

            mainView.View.BackgroundColor = UIColor.White;
            mainView.View.Add (showTable);
            mainView.View.Add (allocate);

            var navController = new UINavigationController (mainView);

            showTable.TouchUpInside += delegate {
                navController.PushViewController (new MyViewController (), true);
                // Not a great idea to call Collect but you could to force it.
                // GC.Collect ();
            };

            allocate.TouchUpInside += delegate {
                // Trigger the GC by creating a bunch of objects
                System.Collections.Generic.List<object> list = new System.Collections.Generic.List <object> ();
                for (int i=0; i<2048; i++)
                {
                    list.Add (new object ());
                }
            };


            window.RootViewController = navController;

            window.MakeKeyAndVisible ();

            return true;
        }
    }

    public class MyViewController : UIViewController
    {
        UITableView _tableView;
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();
            _tableView = new UITableView (this.View.Bounds);
            View.Add (_tableView);

            _tableView.DataSource = new MyDataSource ();
        }

        ~MyViewController ()
        {
            // Bad practice to call other managed objects in finalizer
            // But for sample purposes it will be ok
            Console.WriteLine ("~MyViewController");
        }

        protected override void Dispose (bool disposing)
        {
            // Bad practice to call other managed objects in Dispose
            // But for sample purposes it will be ok
            Console.WriteLine ("MyViewController.Dispose");
            base.Dispose (disposing);
        }

        class MyDataSource : UITableViewDataSource
        {
            public override int RowsInSection (UITableView tableView, int section)
            {
                return 1;
            }

            public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
            {
                var cell = tableView.DequeueReusableCell ("SomeUniqueString");
                if (cell != null)
                    return cell;

                return new TableViewWaitCell (UITableViewCellStyle.Default, "SomeUniqueString");
            }
        }
    }

    public class TableViewWaitCell : UITableViewCell
    {
        public TableViewWaitCell(UITableViewCellStyle style, string reuseIdentifier) : base (style, reuseIdentifier)
        {
            this.SelectionStyle = UITableViewCellSelectionStyle.None;
            this.TextLabel.Text = "Something";
        }

        ~TableViewWaitCell()
        {
            // Bad practice to call other managed objects in finalizer
            // But for sample purposes it will be ok
            System.Console.WriteLine("TableViewWaitCell.~TableViewWaitCell"); 
            // Avoid forcing the GC
            //System.GC.Collect();
        }
        protected override void Dispose (bool disposing)
        {
            // Bad practice to call other managed objects in Dispose
            // But for sample purposes it will be ok
            System.Console.WriteLine("TableViewWaitCell.Dispose");
            base.Dispose (disposing);
            //GC.Collect();
        }
    }
}
于 2013-03-21T04:47:47.323 に答える
0

この問題は、ビューコントローラーのメソッドを参照するEventHandlerが原因で発生したため、セルとコントローラーのコレクションが妨げられていました。

于 2013-04-04T13:43:36.680 に答える