Reputation: 3129
I am building an application that uses a shared project to hold its business logic.
In this shared project each controller has an equivalent.
I use the ViewDidLoad
method to generate the logic for the controller and attach it to itself like this:
public override void ViewDidLoad() {
base.ViewDidLoad();
_logic = new MyControllerLogic();
_logic.attach(this);
}
Each logic has its own instance variables etc that should be disposed when they are not used
So when (for example) I navigate backwards from MyController
to MyFirstController
or if I replace the application's root view controller , the logic behind the navigated out of/replaced controller has to be disposed.
Where should I do this?
In the android part of the project I did it like this:
protected override void OnPause() {
base.OnPause();
if (IsFinishing) {
_logic?.detach();
_logic = null;
}
}
Upvotes: 0
Views: 741
Reputation: 2104
Code should be like this
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;
}
}
Upvotes: 0
Reputation: 3129
For those wandering this is the approach I ended up with (this works for Xamarin but it is adaptable to Swift if one needs to):
I created the following class ,and from now on all my UIViewController
s will extend this class
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);
}
}
The only downside is that from now on I have to always use Present to show new Controllers and Add/ReplaceController to show new Controllers inside the current Navigation.
If someone has a better idea please tell me, because I will have to do the above for all types of controllers (UITabBarController etc etc) and that could be difficult to maintain.
Upvotes: 0
Reputation: 32694
You should use an Unwind Segue on the view controller, this is the only reliable way of knowing when a view controller has been dismissed:
https://developer.apple.com/library/archive/technotes/tn2298/_index.html
Here is a Xamarin example:
https://github.com/xamarin/recipes/tree/master/Recipes/ios/general/storyboard/unwind_segue
Upvotes: 1
Reputation: 1750
Xamarin is C# based an uses the C# garbage collector. The most you should do is call is GC.Collect();
If you want fine-grained control over memory management, you should use Swift or Objective-C.
Upvotes: 0