什么时候应该在Xamarin.IOS本机中处置对象?

时间:2019-02-05 14:48:03

标签: c# xamarin.ios

我正在构建一个使用共享项目来保存其业务逻辑的应用程序。

在此共享项目中,每个控制器都有一个等效项。

我使用T#方法为控制器生成逻辑并将其附加到自身,如下所示:

ViewDidLoad

每个逻辑都有自己的实例变量等,当不使用它们时应将其丢弃

因此,例如(当我)从 public override void ViewDidLoad() { base.ViewDidLoad(); _logic = new MyControllerLogic(); _logic.attach(this); } 向后导航到MyController时,或者如果我替换了应用程序的根视图控制器,则必须处理导航出/替换后的控制器背后的逻辑。 / p>

我应该在哪里做?

在项目的android部分中,我这样做的是:

MyFirstController

4 个答案:

答案 0 :(得分:1)

您应该在视图控制器上使用Unwind Segue,这是知道何时关闭视图控制器的唯一可靠方法:

https://developer.apple.com/library/archive/technotes/tn2298/_index.html

这是一个Xamarin示例:

https://github.com/xamarin/recipes/tree/master/Recipes/ios/general/storyboard/unwind_segue

答案 1 :(得分:0)

Xamarin基于C#,并且使用C#垃圾收集器。您最应该做的就是致电GC.Collect();

如果要对内存管理进行细粒度的控制,则应使用Swift或Objective-C。

答案 2 :(得分:0)

对于那些徘徊的人,这是我最终的方法(这适用于Xamarin,但如果需要的话,它也可以适用于Swift):

我创建了以下课程,从现在开始,我所有的UIViewController都将扩展该课程

public abstract class BaseViewController : UIViewController {
    protected virtual void Finished() { }

    protected virtual void backPressed() { } //this is just in case I wish to be notified when the user moves back

    public override void ViewWillDisappear(bool animated) {
        base.ViewWillDisappear(animated);
        if (NavigationController != null && NavigationController.ViewControllers.ToList().FirstOrDefault(c => c == this) == null) {
            backPressed();
            Finished();
        }
    }

    public override void DismissViewController(bool animated, [BlockProxy(typeof(AdAction))] Action completionHandler) {
        base.DismissViewController(animated, completionHandler);
        Finished();
    }


    public void Present(string storyboard, bool replace = false, bool animated = true) {
        UIViewController vctl = UIStoryboard.FromName(storyboard, null).InstantiateInitialViewController();
        if (replace) {
            List<UIViewController> old = new List<UIViewController>();
            if (UIApplication.SharedApplication.KeyWindow.RootViewController is UINavigationController nav) {
                old.AddRange(nav.ViewControllers);
            } else {
                old.Add(UIApplication.SharedApplication.KeyWindow.RootViewController);
            }
            if (animated) {
                UIView.Transition(
                    UIApplication.SharedApplication.KeyWindow
                    , 0.25
                    , UIViewAnimationOptions.TransitionCrossDissolve
                    , () => UIApplication.SharedApplication.KeyWindow.RootViewController = vctl
                    , () => {
                        old.ForEach(o => (old as BaseViewController)?.Finished());
                    });
            } else {
                UIApplication.SharedApplication.KeyWindow.RootViewController = vctl;
                old.ForEach(o => (old as BaseViewController)?.Finished());
            }
        } else {
            this.PresentViewController(vctl, animated, null));
        }
    }

    public void AddController(string storyboard, string controller = null, bool animated = true) {
        UIViewController ctl = getController(storyboard, controller);
        this.NavigationController?.PushViewController(ctl, animated);
    }

    public static void ReplaceController(this UINavigationController me, string storyboard, string controller = null, bool animated = true) {
        UIViewController ctl = getController(storyboard, controller);
        UIViewController[] vcl = this.NavigationController?.ViewControllers;
        if (vcl == null) return;
        if (vcl.Length > 0) {
            UIViewController old = vcl[vcl.Length - 1];
            vcl[vcl.Length - 1] = ctl;
            me.SetViewControllers(vcl, animated);
            (old as BaseViewController)?.Finished();
        } else {
            me.PushViewController(ctl, animated);
        }

    }

    private UIViewController getController(string storyboard, string controller = null) {
        if (string.IsNullOrWhiteSpace(controller)) {
            return UIStoryboard.FromName(storyboard, null).InstantiateInitialViewController();
        }
        return UIStoryboard.FromName(storyboard, null).InstantiateViewController(controller);
    }

}

唯一的缺点是从现在开始,我必须始终使用Present来显示新的Controllers,并使用Add / ReplaceController来显示当前导航内的新Controllers。

如果有人有更好的主意,请告诉我,因为我必须对所有类型的控制器(UITabBarController等)执行上述操作,而这可能很难维护。

答案 3 :(得分:0)

  1. 第一种方法是编写自己的导航服务并管理视图控制器。而且当您使用GoBack时,您可以为弹出的ViewController执行Dispose方法。
  2. 第二个是使用框架,例如MvvmLight,MvvmCross等。当您清理/处置/取消订阅等内容时,它会在ViewModel(您的业务逻辑)中提供方法。

代码应像这样

public class NavigationService
{
   public void NavigateTo(string storyboardName)
   {
      //your logic to present storyboard
   }

   public void GoBack()
  {
     var poppedController = NavigationController.PopViewController(true);
     poppedController.Dispose(); //or your method where you want preclean data;
  }
}