2016-01-26 17 views
6

UIViewController alt sınıfına sahibim, bu da UITableViewController == HUDTableViewController'u taklit eder. Sonra bu alt sınıf görüntü denetleyicisinden alt sınıfını (SomeViewController : HUDTableViewController).UIViewController alt sınıfı (UITableViewController'ı taklit eder) yayınlanmadı

Bir bellek uyarısı taklit edersem SomeViewController yayımlanamaz. İşte HUDTableViewController ait kodudur:

using System; 

using Foundation; 
using UIKit; 

namespace MyApp 
{ 
    public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable, IUIScrollViewDelegate 
    { 
     private UIView parentView; 
     private UITableView tableView; 

     public UITableView TableView 
     { 
      get 
      { 
       return this.tableView; 
      } 
      set 
      { 
       this.tableView = value; 
      } 
     } 

     public HUDTableViewController() : base() 
     { 
      Initialize(); 
     } 

     private void Initialize() 
     { 
      this.tableView = new UITableView(); 
      this.tableView.TranslatesAutoresizingMaskIntoConstraints = false; 

      this.tableView.WeakDelegate = this; 
      this.tableView.WeakDataSource = this; 

      this.parentView = new UIView(); 
     } 

     public override void ViewDidLoad() 
     { 
      base.ViewDidLoad(); 

      this.parentView.AddSubview(this.tableView); 
      View = this.parentView; 

      NSMutableDictionary viewsDictionary = new NSMutableDictionary(); 
      viewsDictionary["parent"] = this.parentView; 
      viewsDictionary["tableView"] = this.tableView; 

      this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary)); 
      this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary)); 
     } 

     [Foundation.Export("numberOfSectionsInTableView:")] 
     public virtual System.nint NumberOfSections(UIKit.UITableView tableView) 
     { 
      return 1; 
     } 

     public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section) 
     { 
      throw new NotImplementedException(); 
     } 

     public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath) 
     { 
      throw new NotImplementedException(); 
     } 

     [Export("tableView:estimatedHeightForRowAtIndexPath:")] 
     public virtual System.nfloat EstimatedHeight(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath) 
     { 
      return UITableView.AutomaticDimension; 
     } 

     [Foundation.Export("tableView:didSelectRowAtIndexPath:")] 
     public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath) 
     { 
     } 

     [Export("tableView:heightForRowAtIndexPath:")] 
     public virtual System.nfloat GetHeightForRow(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath) 
     { 
      return 44.0f; 
     } 

     [Foundation.Export("tableView:heightForHeaderInSection:")] 
     public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section) 
     { 
      return UITableView.AutomaticDimension; 
     } 

     [Foundation.Export("tableView:viewForHeaderInSection:")] 
     public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section) 
     { 
      return null; 
     } 

     [Export("tableView:titleForHeaderInSection:")] 
     public virtual string TitleForHeader(UITableView tableView, nint section) 
     { 
      return string.Empty; 
     } 

     [Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")] 
     public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath) 
     { 
     } 
    } 
} 

tableView referans 2 sayısı gösterilir (çünkü AddSubView ve benim mal) olması gerekir. SomeEventHandler arasında, çünkü SomeViewControllerMasterViewContainer bir referans yer alır görüldüğü gibi

public class MasterViewContainer : UIViewController 
{ 
    private bool hasSetupHandlersAndEvents = false; 
    // ... 

    public override void ViewWillAppear (bool animated) 
    { 
     base.ViewWillAppear (animated); 

     if (!hasSetupHandlersAndEvents) { 
      if (listButton != null) { 
       listButton.Clicked += listButton_Clicked; 
      } 
      hasSetupHandlersAndEvents = true; 
     } 
    } 

    public override void ViewWillDisappear (bool animated) 
    { 
     base.ViewWillDisappear (animated); 

     if (hasSetupHandlersAndEvents) { 
      if (listButton != null) { 
       listButton.Clicked -= listButton_Clicked; 
      } 
      hasSetupHandlersAndEvents = false; 
     } 
    } 

    private void listButton_Clicked(object sender, EventArgs args){ 
     SomeViewController viewController = new SomeViewController(); 
     viewController.SomeEvent += SomeEventHandler; 
     NavigationController.PushViewController(viewController, false); 
    } 
} 

:

Bu SomeViewController başlatır ana görünümü kontrol cihazıdır. Ben

public class SomeViewController : UITableViewController 

kullanırsanız

SomeViewController serbest bırakılır ama

public class SomeViewController : HUDTableViewController 

Dispose yöntemi asla denir kullanırsak serbest bırakılmaz. Bir referans döngüsü görmüyorum. Bir şeyi nasıl bırakmak zorundayım? Neyi özlüyorum?

1 deneyin:

Bu aklıma gelen tek çözümdür. Referansı SomeViewController tuttuğum bir alan (sınıf değişkeni) kullanıyorum. DidReceiveMemoryWarning'da manuel olarak serbest bırakıyorum/atın. Alana erişmek istediğimde, daha önce başlatılmış olup olmadığını kontrol ediyorum. Gerekmiyorsa, gerektiğinde başlatabilirim.

public class MasterViewContainer : UIViewController 
{ 
    private SomeViewController viewController; 

    public override void DidReceiveMemoryWarning() 
    { 
     // Releases the view if it doesn't have a superview. 
     base.DidReceiveMemoryWarning(); 

     // Release any cached data, images, etc that aren't in use. 
     if (this.viewController != null) 
     { 
      this.viewController.SomeEvent -= SomeEventHandler; 
      this.viewController.Dispose(); 
      this.viewController = null; 
     } 
    } 

    private void listButton_Clicked(object sender, EventArgs args){ 
     if (this.viewController == null) 
     { 
      this.viewController = new SomeViewController(); 
      this.viewController.SomeEvent += SomeEventHandler; 
     } 

     NavigationController.PushViewController(this.viewController, false); 
    } 

Ancak bu çözüm mükemmel değildir. Dispose, görünüm şu anda ekranda görüntülendiğinde de çağrılır. Bu yüzden arızaların olması çok muhtemeldir.

Bounty: Ben bellek yönetim sorunu açıklayan bir çözüm olmasını istiyorum

. Neden serbest bırakılmıyor? Serbest bırakmak için ne değişmeli (denemem gibi şeyler yapmadan). UITableViewController gibi davranmalıdır.

2 deneyin:

Şimdi Dispose(bool disposing)HUDTableViewController ait geçersiz kılmak için çalıştı: Ne HUDTableViewController bu Dispose yöntem ne de SomeViewController ait Dispose yöntem

protected override void Dispose(bool disposing) 
{ 
    if(!this.disposed) 
    { 
     if(disposing) 
     { 
      this.tableView.RemoveFromSuperview(); 
      this.tableView.Dispose(); 
     } 
     this.disposed = true; 
    } 
    base.Dispose(disposing); 
} 

denir.

+0

Bunun için ne gerekir? ViewDidLoad'da oluşturulacağı garanti edilen denetleyici için zaten bir kök görünümü var. Bu nedenle, tablonun alt görünümü olarak tableView eklemek yerine, * parentview'ınızla * değiştirin. Orijinal görünüm, hiyerarşide devam edebilir ve denetleyiciye başvuruda bulunabilir, böylece ikincisi serbest bırakılmaz. –

+0

Bu 'HUDTableViewController' kullanıyorum çünkü üzerinde bir yükleme döndürücü merkezlemek istiyorum. Bu yüzden daha fazla çaba harcamadan bu sınıfı kullanabilirim. Merkezleme için, 'ViewView' ('UITableView' olan) çalışmıyor ve 'UITableView'ün ebeveyini kullanmayı denedim. Referansı bir şekilde serbest bırakan bazı seçenekler var mı? Ya da belki de bir 'UITableView' içinde bir görüntüyü merkezileştiren daha iyi bir fikriniz var. – testing

+0

Dispose() yöntemini açık bir şekilde uygulamanız gerekmiyor mu? –

cevap

0

Ebeveyn görünümünüzün de aynı işlevi çağırmasını istiyorsanız süper arayın, yönetiminizi oradan yönetin. Düzenlemeye bağlı olarak, başka bir manuel atma işlemi yapmanız gerekmez.

public override void DidReceiveMemoryWarning() 
{ 
    // If you want the superclass to fire the function first call super first 
    // and vice versa. 
    super.didReceiveMemoryWarning(); 
    // Releases the view if it doesn't have a superview. 
    base.DidReceiveMemoryWarning(); 
İlgili konular