iOS View Controllers not being released? - c#

(I'm using c#/Xamarin, but doubt the issue is specific to that.)
When I add a View Controller and then remove it - it's DidReceiveMemoryWarning is still called (in the Simulator and on real devices), so it can't have been released. I've narrowed it down to this:-
UIViewController vc=(UIViewController)this.Storyboard.InstantiateViewController(identifier);
this.AddChildViewController(vc);
vc.RemoveFromParentViewController();
vc=null;
and calling DidMoveToParentViewController and WillMoveToParentViewController (as described in the docs) doesn't help either:
UIViewController vc=(UIViewController)this.Storyboard.InstantiateViewController(identifier);
this.AddChildViewController(vc);
vc.DidMoveToParentViewController(this);
vc.WillMoveToParentViewController(null);
vc.RemoveFromParentViewController();
vc=null;
then simulate a memory warning and vc DidReceiveMemoryWarning gets called even though there is no reference to it. How is this possible when it's been removed as child controller and there is no reference to it.
(The same is happening when I use a segue set up in a Storyboard to go to a detail view in a UINavigationController, for example, after going "back" to the root controller, the detail controller still gets DidReceiveMemoryWarning messages.
Any help to understand this would be appreciated
UPDATE:
Now the problem I have is with a simple UIViewController embedded in a UINavigationController
I add the navigation controller:
this.nc=(UINavigationController)this.Storyboard.InstantiateViewController("NavigationController");
this.AddChildViewController(this.nc);
this.nc.DidMoveToParentViewController(this);
and remove later (after it's loaded):
this.nc.WillMoveToParentViewController(null);
this.nc.RemoveFromParentViewController();
this.nc=null;
and this all works fine (it's not retained). BUT if I add this simple line in the ViewDidLoad method of the ViewController thats embedded, then the ViewController IS retained!
Console.WriteLine("this.NavigationController={0}",this.NavigationController);
ie, just accessing "this.NavigationController" causes the VC to be retained!
So each time I run it, I get another ViewController retained!
Any ideas?

It could be that your view controller’s initialization method has some side effect causing it to stay alive. A common example would be that it creates an NSTimer object, which retains its target. Go through the methods that are called when the view controller is instantiated from the storyboard and see if anything retains it.

Related

Navigation within Page using Template10

I have problem how to implement sub-page navigation in UWP. The page is in RootFrame, which I can use on navigation. But i want to use something like this:
<Page>
<Grid>
<Frame x:Name="MyFrame"/>
</Grid>
</Page>
What I want is, use Navigate method of control MyFrame in ViewModel. I can call the method from code-behind, but I'm developing my app using MVVM. I'm not sure, if Template10 can work with sub-frames.
I appreciate any advice.
EDIT:
More details:
I have pivot control which is in page. the pivot has 2 tabs (pivotitems). The content of the pivotitem must be navigable. What I mean: I pivotitem 1, I need to have one Frame and use it for navigation in the pivotitem. My problem is, how to use or how to call the frame in pivotitem from ViewModel, especially I need to call Navigate method. Now I'm using Template10's navigation service and it's working with rootframe. I don't know, how to use it for other let's say sub-frames.
You can always do this.
var nav = Bootstrapper.NavigationServiceFactory(BackButton.Attach, ExistingContent.Exclude, this.Frame);
This will give you a navigation service for the frame in your page. You can then use session state, if you like.
Bootstapper.SessionState["MyNav"] = nav;
From here your view-model can access the service and navigate. You can repeat this for as many frames as you have. And you can then handle navigation in your view-model without consideration of "where" the frame is, just that your logic requires it to nav.
Does this make sense?
I don't know how you are going to trigger the navigation change so I'll assume it will start from a button click. I am also assuming the button's Command property is already bound to an ICommand in the viewmodel (the same concepts can be applied to different kinds of views).
All we have to do now is to make the ICommand implementation call our custom NavigationService to perform the content switch. This NavigationService class will be nothing but a simple proxy to the window global frame. Its main navigation method can be as simples as:
public void Switch()
{
var rootFrame = Window.Current.Content as Frame;
if ((rootFrame.Content as ParentPage) != null)
{
rootFrame.Navigate(typeof(ChildPage));
}
}
So you have tagged this with Template10 but it seems to be a more general question for UWP as a whole. I wonder if you have considered all of the inherent complexities with this approach - specifically related to suspension and resume. For each frame you have, you would need to save and restore navigation state, which isn't straight-forward when you have nested frames. Have you also considered how global navigation would work?
Template 10 does support the concept of multiple NavigationServices and, therefore, multiple frames, but only from the perspective of you can create them. Template10 does not inherently understand how such frames may be related to each other, so cannot perform automatic back propagation where you have something like:
FrameA[Main->Page1->Page1:Pivot1.FrameB[View1->View2->View3]]
Here we have two frames - FrameA and FrameB. FrameA has navigated from
Main to Page1. Page1 has a Pivot that hosts FrameB in PivotItem1 and
FrameB has navigated from View1 to View 2 and from View2 to View 3.
Global navigation (i.e. the shell back, etc.) would be automatically wired to FrameA, so you would need to intercept that action, and then handle you own navigation activity for FrameB.
Take a look at the BackButtonBehavior to see how it is possible to intercept the global back and then put in place your own action.
I don't know if you can do something like that..
One possible workaround is to use a Messenger that sends a message from your viewmodel to the view's code behind.. I'm not a fan of this solution though, because as I said before you have to use the page's code behind..

Xamarin.iOS AutoLayouts (Cirrious.FluentLayout) and PresentViewController weird behvaior

I am seeing constraints errors in my output window when I invoke a UIViewController using PresentViewController
Here is what my view heirarchy looks like:
MainViewController (RootViewController)
Outer MainVC Button
Nested UINavigationController (Nav1)
FirstViewController (Nav1.RootViewController)
Nested FirstVC Button
MyModalViewController (Presented by invoking PresentViewController)
dismiss button
Everything works as expected when MyModalViewController is shown from the Outer MainVC Button, but when I do the same from the Nested FirstVCButton and dismiss it to return back, I get constraint errors and the Nav1 is gone from the MainViewController
I just want to understand why this is happening and any potential workarounds are also welcome.
Full Source Code replicating this issue can be found here
https://github.com/raghurana/XamarinIosAutoLayoutBug
Edit
It's a requirement to present MyModalViewController (well modally, thus PresentViewController instead of Push Or Show) due to UX design requirements.

Caliburn.Micro - OnDeactivate Not triggering

I'm having a strange issue, and im pretty much at my wits end trying to work it out.
I have a Conductor which activates and deactivates viewmodels used for editing data, these view models implements screen and use OnDeactivate to ensure that any changes are saved before closing.
However for some reason, OnDeactivate in one of my ViewModels is never called, even tho i can see it being passed to DeactivateItem of the conductor.
To do this have the following in my conductor:
private void SwitchScreen(Screen viewModel)
{
DeactivateItem(ActiveItem, true);
ActivateItem(viewModel);
NotifyOfPropertyChange(() => ProjectActionRegion);
}
public override void DeactivateItem(IScreen item, bool close)
{
base.DeactivateItem(item, close);
NotifyOfPropertyChange(() => ProjectActionRegion);
}
This ensures that when TryClose is called the region is correctly updated. The SwitchScreen is called each time a selection is made on a datagrid, loading the viewmodel. I can see that Deactivate item is called when i change selection, and i can see its passing the correct viewmodel into that method.
However OnDeactivate is still never called, and i have no idea why :/
protected override void OnDeactivate(bool close)
{
System.Windows.Forms.MessageBox.Show("SAVE ME!");
}
Edited to remove incorrect code (the base. was a mistake, this is my actual code)
EDIT:
I've just realized what the difference between the working versions and the broken version is. I have a view/viewmodel that works as a conductor, this works fine. However inside that viewmodel i load a second view/viewmodel that also works as a conductor, this one fails to work, i wonder if it has to do with with being inside another conductor (but not actually handled by that conductor, just loaded into that viewmodel)
For screen life-cycle to function correctly, all of the view models in your view hierarchy must be conducted. You should make your child conductor an active screen of your parent conductor.
You can either do this by making it the active item of the parent conductor, or by using the ConductWith method on the child conductor, passing in a reference to the parent conductor.

Transition between views by navigation controller. ignoring tabbarcontroller

There is a problem , I have one available repose collection ViewController. At the same representation have a button switch to another View. Between the repose organized transitions (navigation controller). Clicking on the back button in the second presentation is called ViewDidAppear is good. But I also have an application has tabBarController. And when you click on the first View on the panel tabBar called again ViewDidAppear. Although he no longer needs to be called . Tell me how can I do so that does not cause tabbar ViewDidAppear. A caused only navigationController? Thank you!
ViewDidAppear will be called every time a ViewController is displayed is shown on the screen.
ViewDidLoad is called only when the View is loaded. So for example, if you present a modal view from a view controller (parent vc), then when the modal is dismissed, the parent vc will NOT have its ViewDidLoad method called. Instead it will have ViewWillAppear and ViewDidApper called only.
Moving the code you only want called once to ViewDidLoad should solve your problem.

Error Creating Control - Custom Control

I have a custom control and it works fine...except that the control cannot be rendered on Design Time. ( I am using VS 2008)
I am thinking many people who develop custom controls encounter this problem...The error I get is "Error Creating Control - CustomControlName" Object reference not set to an instance of an object.
I want a work around. or at least debug this...(Since this is a design time issue how to debug?)
I have tried if( !DesignMode) code on OnInit, OnPreRender, RenderContents, CreateChildControls Methods ( I am just shooting in the dark)...
Help pls. I really hope this is not a VS bug!
BFree's comment is the most likely issue, for a control to display in the design view it needs a parameterless constructor as the design viewer doesn't know how you would normally instantiate the control.
If you do have a parameterless constructor, can you paste some code in to show what's happening?
As Glenn mentioned the first issue could be no parameterless constructor.
The second could be you are calling methods during the OnLoad or other methods you mentioned that have parameters that are not initialized or some sort of attempt at database calls etc that is normally done at run-time.
Unless they fixed this bug recently* and I'm not aware, something to keep in mind is the DesignMode property works for the first and second level of nested controls but beyond that it normally doesn't work right. (Such as form containing a UserControl[1] that holds another UserControl[2], the DesignMode works on the form and [1] but not [2]).
Also to agree with Glenn, seeing some of the code will help.
*From my very recent experience working with nested usercontrols it hasn't been fixed.
In your OnPreRender & CreateChildControls methods it's making a call to this.Page. You might want to try wrapping them in a
if (this.Page != null)
{
.....
}
Because I don't think you'll have a Page object at that point & I'm pretty sure PreRender & CreateChildControls will be called in design view. I haven't written custom server controls for a while though, so I could be wrong (been working in MVC lately).
Glenn, the error ur getting a VS bug and no fix has been released yet.

Categories