Monotouch (Xamarin.iOS) memory leaks - c#

I have an app with a complicated view hierarchy, where one view controller (let's call it RootVC) can lead to many others. When I pop RootVC, I want to completely release it. I didn't store the reference in a field or elsewhere and believed that it would be enough. But recently I checked Xamarin's Heap Shot and saw in the "All objects" section that many instances of RootVC remain in memory.
For example this:
sealed class VC1 : UIViewController
{
...
private void OpenVC2()
{
var vc2 = new VC2();
NavigationController.PushViewController(vc2, true);
}
}
sealed class VC2 : UIViewController
{
private UIButton button;
public override ViewDidLoad()
{
...
button = new UIButton(frame);
button.TouchUpInside += HandleButtonTouch;
...
}
private void HandleButtonTouch(object sender, EventArgs e)
{
NavigationController.PopViewControllerAnimated(true):
}
}
Here's the link to the screenshots of Heap Shot (can't post them as images because of low reputation) - http://imgur.com/a/3MYBr#1
When I'm on VC2, I see something like on the first screenshot.
When I pop VC2 and on VC1, Heap Shot look like on the second image.
After a few VC2 appearing it looks like the third screenshot.
And they never get disposed or finalized, they remain till the end. Even through they are not reachable via roots. Which is not acceptable because memory is limited and with all these VC2's in memory we can easily get memory warning or app terminating.
But if I subscribe/unsubscribe to button events on View appearing/disappearing like this:
sealed class VC2 : UIViewController
{
private UIButton button;
public override ViewDidLoad()
{
...
button = new UIButton(frame);
...
}
public override void ViewWillAppear(bool animated)
{
...
button.TouchUpInside += HandleButtonTouch;
}
public override void ViewDidDisappear(bool animated)
{
...
button.TouchUpInside -= HandleButtonTouch;
}
private void HandleButtonTouch(object sender, EventArgs e)
{
NavigationController.PopViewControllerAnimated(true):
}
}
In this case VC2 (with all its views, etc) gets disposed properly when it disappears. ~VC2() is called and all VC2's are no longer visible in Heap Shot.
So, here's the question. What I am doing wrong? Should I subscribe/unsubscribe from control events like above? Or it's a Xamarin.iOS's memory leak?

What happens is that there is a circular dependency (with the event handlers) that crosses the native-managed boundary, and currently the Xamarin.iOS runtime/GC is not able to detect this.
You've already found the fix for this problem: break the circular dependency by removing event handlers.
Here is a video explaining the situation in detail: http://xamarin.com/evolve/2013#session-0w86u7bco2

Related

Xamarin.Android, How to call another method from another .cs file

Needed some help here, so I tried to run method from another .cs, I had the following code running in my mainActivity.cs
protected override void OnCreate(Bundle savedInstanceState)
{
startGame();
}
public void startGame()
{
firstNum = FindViewById<TextView>(Resource.Id.tvFirstNum);
secondNum = FindViewById<TextView>(Resource.Id.tvSecondNum);
firstNum.Text = Convert.ToString(2);
secondNum.Text = Convert.ToString(2);
}
Heres the thing, I tried to run the code from another CS file
private void BtnRestart_Click(object sender, EventArgs e)
{
MainActivity mp = new MainActivity();
mp.startGame();
}
However I got the error of
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.app.Activity.findViewById(int)' on a null
object reference
Does anyone know why?
Thanks!
You are instantiating your MainActivity class yourself, which does not load the accompanying Layout. That's because the lifecycle methods that Android uses aren't called, so your OnCreate method will never fire (which usually handles the layout). Therefore the FindViewById will return a null value.
A note: You shouldn't call views from another class (especially if it's another Activity) like you are trying to do here. If you still want to call this from another class, you can pass the Activity as a parameter, but I wouldn't recommend that approach.
I would recommend you to read the Activity Lifecycle documentation.

How to stop my WPF usercontrol from loading, if i have basecontrol

I have a BaseControl, of which almost all my controls inherit from.
Right now I am working on security and I want to block users from viewing certain items if they do not have access.
I am able to do so on the Loaded event of the base control, but this is too late, this meanse the whole control gets rendered, and then replaced. I would like to replace it before it renders
here is an example of my code:
public class BaseControl : UserControl
{
public BaseControl()
{
this.Loaded +=BaseControl_Loaded;
}
private void BaseControl_Loaded(object sender, RoutedEventArgs e)
{
if (!userHasAccess)
{
this.Content = new AccessDenied();
}
}
}
The above code works perfectly, but a bit too late, Is there a way that I can do this before the Loaded event?
You want to override the OnInitialized where the constructor and properties are being set up before the Render happens.
protected override void OnInitialized(EventArgs e)
{
if (!userHasAccess)
{
this.Content = new AccessDenied();
}
base.OnInitialized(e);
}
More information can be found here.
Check out following sites:
http://msdn.microsoft.com/en-us/library/ms745025(v=vs.110).aspx
Also check object lifetime events that is what you asking for.
http://msdn.microsoft.com/en-us/library/ms754221(v=vs.110).aspx

Windows Forms, Designer, and Singleton

I'm trying to work with Windows Forms and User Controls and thus far it's been nothing but a headache. I can't make the form or the controls static because the designer doesn't like that and when I use Singleton on my form and controls, the designer still throws errors at me.
My FormMain:
public partial class FormMain : Form
{
private static FormMain inst;
public static FormMain Instance
{
get
{
if (inst == null || inst.IsDisposed)
inst = new FormMain();
return inst;
}
}
private FormMain()
{
inst = this;
InitializeComponent();
}
MainScreen.cs:
public partial class MainScreen : UserControl
{
private static MainScreen inst;
public static MainScreen Instance
{
get
{
if (inst == null || inst.IsDisposed)
inst = new MainScreen();
return inst;
}
}
private MainScreen()
{
inst = this;
InitializeComponent();
}
If the constructor of MainScreen is public the program runs, but when I change it to private I now get an error in FormMain.Designer.cs saying "'Adventurers_of_Wintercrest.UserControls.MainScreen.MainScreen()' is inaccessible due to its protection level". It points to this line:
this.controlMainScreen = new Adventurers_of_Wintercrest.UserControls.MainScreen();
I think this is the instance of the class that the designer makes by default. Should I ditch the designer? Or is there a way around this? Or is there another way to make class properties accessible without using Singleton (since I can't seem to make the form or controls static)? Any help would be greatly appreciated.
You need to keep a reference to each instance of each form if you want to access the public properties of the instantiated form.
One way is to have a class with a static variable for each type of form:
class FormReferenceHolder
{
public static Form1 form1;
public static Form2 form2;
}
This way you would set the static variable whenever you instantiate a form, and then you can access that variable from anywhere in the program. You can go one step further with this and use properties that set up the form if it doesn't already exist:
class FormReferenceHolder
{
private static Form1 form1;
public static Form1 Form1
{
get
{
if (form1 == null) form1 = new Form1();
return form1 ;
}
}
}
...
static void Main()
{
Application.Run(FormReferenceHolder.Form1 );
}
I think I answered a previous question about this, which looks like it is what got you started down this route. The first point is that I wasn't recommending this pattern specifically, just trying to teach you more about how software developers can manage scope.
That said, the problem you are facing isn't insurmountable. You could hobble a public constructor by throwing an exception at runtime and not at design time, for instance, and modify Program.cs to use the static Instance instead of manually constructing the form.
But.
As I said in the other question, the better option would be to change architecture so that you don't need your library code to directly manipulate the GUI in the first place.
You can do this either by just having the GUI ask the library questions when it thinks it needs new data (simple functions) or by letting the GUI be notified when something needs to change. Either method would be better than having the library fiddle with labels directly.
A good place to start would be something like an MVC (model-view-controller) architecture, which I was alluding to in my previous answer. It might be best, though, to give us an idea of what your high-level program structure looks like now on a bit more detail. What are the main classes you are using in your system (not just the ones you've mentioned so far)? What is the main responsibility of each, and where does each live? Then our recommendations could be a little more specific.
EDIT
So, I have mocked up a quick demo of a possible alternative architecture, based on your comment.
I have the following in my project:
FormMain (Form)
TitleScreen (UserControl)
InGameMenu (UserControl)
MainScreen (UserControl)
GameController (Class)
GameModel (Class)
I didn't use Date and LoadSave, for now.
FormMain simply has an instance of each UserControl dropped on it. No special code.
GameController is a singleton (since you tried to use this pattern already and I think it would be helpful for you to try using a working version of it) that responds to user input by manipulating the model. Note well: you don't manipulate the model directly from your GUI (which is the View part of model-view-controller). It exposes an instance of GameModel and has a bunch of methods that let you perform game actions like loading/saving, ending a turn, etc.
GameModel is where all your game state is stored. In this case, that's just a Date and a turn counter (as if this were going to be a turn-based game). The date is a string (in my game world, dates are presented in the format "Eschaton 23, 3834.4"), and each turn is a day.
TitleScreen and InGameMenu each just have one button, for clarity. In theory (not implementation), TitleScreen lets you start a new game and InGameMenu lets you load an existing one.
So with the introductions out of the way, here's the code.
GameModel:
public class GameModel
{
string displayDate = "Eschaton 23, 3834.4 (default value for illustration, never actually used)";
public GameModel()
{
// Initialize to 0 and then increment immediately. This is a hack to start on turn 1 and to have the game
// date be initialized to day 1.
incrementableDayNumber = 0;
IncrementDate();
}
public void PretendToLoadAGame(string gameDate)
{
DisplayDate = gameDate;
incrementableDayNumber = 1;
}
public string DisplayDate
{
get { return displayDate; }
set
{
// set the internal value
displayDate = value;
// notify the View of the change in Date
if (DateChanged != null)
DateChanged(this, EventArgs.Empty);
}
}
public event EventHandler DateChanged;
// use similar techniques to handle other properties, like
int incrementableDayNumber;
public void IncrementDate()
{
incrementableDayNumber++;
DisplayDate = "Eschaton " + incrementableDayNumber + ", 9994.9 (from turn end)";
}
}
Things to note: your model has an event (in this case, just one of type EventHandler; you could create more expressive types of events later, but let's start simple) called DateChanged. This will be fired whenever DisplayDate changes. You can see how that happens when you look at the property definition: the set accessor (which you will NOT call from your GUI) raises the event if anyone is listening. There are also internal fields to store game state and methods which GameController (not your GUI) will call as required.
GameController looks like this:
public class GameController
{
private static GameController instance;
public static GameController Instance
{
get
{
if (instance == null)
instance = new GameController();
return instance;
}
}
private GameController()
{
Model = new GameModel();
}
public void LoadSavedGame(string file)
{
// set all the state as saved from file. Since this could involve initialization
// code that could be shared with LoadNewGame, for instance, you could move this logic
// to a method on the model. Lots of options, as usual in software development.
Model.PretendToLoadAGame("Eschaton 93, 9776.9 (Debug: LoadSavedGame)");
}
public void LoadNewGame()
{
Model.PretendToLoadAGame("Eschaton 12, 9772.3 (Debug: LoadNewGame)");
}
public void SaveGame()
{
// to do
}
// Increment the date
public void EndTurn()
{
Model.IncrementDate();
}
public GameModel Model
{
get;
private set;
}
}
At the top you see the singleton implementation. Then comes the constructor, which makes sure there's always a model around, and methods to load and save games. (In this case I don't change the instance of GameModel even when a new game is loaded. The reason is that GameModel has events and I don't want listeners to have to unwire and rewire them in this simple sample code. You can decide how you want to approach this on your own.) Notice that these methods basically implement all the high-level actions your GUI might need to perform on the game state: load or save a game, end a turn, etc.
Now the rest is easy.
TitleScreen:
public partial class TitleScreen : UserControl
{
public TitleScreen()
{
InitializeComponent();
}
private void btnLoadNew(object sender, EventArgs e)
{
GameController.Instance.LoadNewGame();
}
}
InGameMenu:
public partial class InGameMenu : UserControl
{
public InGameMenu()
{
InitializeComponent();
}
private void btnLoadSaved_Click(object sender, EventArgs e)
{
GameController.Instance.LoadSavedGame("test");
}
}
Notice how these two do nothing but call methods on the Controller. Easy.
public partial class MainScreen : UserControl
{
public MainScreen()
{
InitializeComponent();
GameController.Instance.Model.DateChanged += Model_DateChanged;
lblDate.Text = GameController.Instance.Model.DisplayDate;
}
void Model_DateChanged(object sender, EventArgs e)
{
lblDate.Text = GameController.Instance.Model.DisplayDate;
}
void Instance_CurrentGameChanged(object sender, EventArgs e)
{
throw new NotImplementedException();
}
private void btnEndTurn_Click(object sender, EventArgs e)
{
GameController.Instance.EndTurn();
}
}
This is a little more involved, but not very. The key is, it wires up the DateChanged event on the model. This way it can be notified when the date is incremented. I also implemented another game function (end turn) in a button here.
If you duplicate this and run it, you'll find that the game date is manipulated from lots of places, and the label is always updated properly. Best of all, your controller and model don't actually know anything at all about the View-- not even that it's based on WinForms. You could as easily use those two classes in a Windows Phone or Mono context as anything else.
Does this clarify some of the architecture principles I and others have been trying to explain?
In essence the problem is that when the application runs, it's going to try to instantiate the main form-window. But by using the Singleton pattern, you're essentially forbidding the application from doing that.
Take a look at the sample code here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.aspx
You'll notice in particular this section:
[STAThread]
public static void Main()
{
// Start the application.
Application.Run(new Form1());
}
Notice how the program is trying to instantiate Form1. Your code says, nah, I don't really want that since you mark the constructor as private (same holds true for static forms as well). But that's counter to how windows forms is supposed to work. If you want a singleton form-window, just don't make any more. Simple as that.

Event handler memory leak using ChildWindows

I just want to ensure that the code below will not be causing the ChildWindow Login in this case to never be collected by the GC. Just to clarify the sample this comes from a silverlight page that is inherited by all other pages therefore the virtual void pageloaded method.
public class MyPage : Page
{
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_user = App.AuthenticatedUser;
if (!_user.IsValid)
{
Login loginWindow = new Login(_user);
loginWindow.Closed += new EventHandler(PageLoaded);
loginWindow.Show();
}
else
PageLoaded(this, e);
}
//to be overridden by the pages extending this page control
protected virtual void PageLoaded(object sender, EventArgs e) { }
Thanks for your help.
This is fine. The loginWindows's Close event knows of your handler, not the other way around, so the form will not have any ties preventing the GC from picking it up.
Unregistering event handlers becomes important if the object your event is defined on will persist in the application for a long time (and you do not want the event handler association to persist for the same duration).

How to create an event by a self-made control in WinForms?

I am working on my first C# and .NET project that uses WinForms, as WPF would be an overkill for our purposes. I created a so-called ButtonMenu that comprises of all menu points, which are buttons. This class is derived from the Windows class Control.
One of the buttons of the ButtonMenu is the "Culture" button that, when pressed in this single-touch application, should change the language of all the forms the application has.
Originally, the ButtonMenu was just a kind of overlay class that accessed the controls of the BaseForm and contained methods. The BaseForm was holding the buttons inside a GroupBox of its own. Later, I run into problems with this kind of design and decided to make a separate control out of it.
My question
How can I create an event (or something similar to it) that can be caught by BaseForm, where the ButtonMenu is placed? The BaseForm can currently not react on this event and cannot change the language of all its own controls, such as text fields and buttons.
Thank you for your help!
What I have tried till now is shown below. Unfortunately, I cannot reach the marked line.
public class BaseForm : Form
{
[…]
protected static ButtonMenu m_ButtonMenu = null;
protected override void OnResize(EventArgs e)
{
[…]
m_ButtonMenu = ButtonMenu.GetInstance(m_CurrentCulture, Size);
m_ButtonMenu.Visible = true;
[…]
}
public override void UpdateWidgets()
{
[…]
try
{
[…]
// Translate button menu into current language:
m_ButtonMenu.AdaptButtons(m_CurrentCulture);
}
catch (ArgumentOutOfRangeException aaore)
{
[…]
[…]
}
protected void InitializeWidgets()
{
{
string strMethod = Name + ":InitializeWidgets(): ";
m_ButtonMenu = ButtonMenu.GetInstance(m_CurrentCulture, Size);
SuspendLayout();
Controls.Add(m_ButtonMenu);
m_ButtonMenu.Top = Height - m_ButtonMenu.Height;
ResumeLayout();
[…]
m_ButtonMenu.Click += new System.EventHandler(this.ButtonMenu_CultureClick);
}
private void ButtonMenu_CultureClick(object sender, EventArgs eas)
{
int iSelection = listViewMessages.SelectedIndices[0]; // <<<<< NEVER REACHED!
[…]
}
Just define an event in your class.
Whenever you want it to fire, call it.
// field
event EventHandler somethingHappened;
// in a method:
var threadSafeCopy = somethingHappened;
if(threadSafeCopy != null)
{
threadSafeCopy(this, e);
}
Where e is an instance of EventArgs or a sub type of EventArgs.

Categories

Resources