1

In Xamarin documentation for Foundation.NSObject, in Lifecycle section, it says:

C# NSObjects are also created on demand when you invoke a method or a property that returns an NSObject. At this point, the runtime will look into an object cache and determine whether a given Objective-C NSObject has already been surfaced to the managed world or not. If the object has been surfaced, the existing object will be returned, otherwise a constructor that takes an IntPtr as a parameter is invoked to construct the object.

Is there a way to do the above from my code? In other words, given an IntPtr handle, can I get a C# NSObject if it already exists or let Xamarin create a new one if it doesn't?

The reason I want to do the above is that I want to keep the IntPtr handle of a C# NSObject and then Dispose() it. Later in the code, I want to get the NSObject back from that IntPtr.

The reason I want to do the above is that I've read enough documentation, blogs and SO questions about the interaction between the C# garbage collector and the native refcounted objects in Xamarin.iOS that I decided to Dispose() everything as soon as possible. So in all methods, I use using whenever I get an NSObject argument. For example:

[Foundation.Action("buttonPressed:")]
public void RatingButtonTapped(UIButton button) {
    using (button) {
        Console.WriteLine("Hello world");
    }
}

So if I had kept a reference to the UIButton earlier during initialization, it will be disposed when this action is run. So instead, I plan to keep the IntPtr handle instead and re-get the UIButton when I need it later.

Community
  • 1
  • 1
imgx64
  • 4,062
  • 5
  • 28
  • 44

1 Answers1

7

You can use this method to get the managed object for a handle:

ObjCRuntime.Runtime.GetNSObject (handle);

But have in mind that if the native object has been freed, you will crash.

If you don't want to crash, you need to retain the native handle, and then release it when you don't need it anymore.

If you add logic to retain+release the native handle, then you can just as well keep the managed object around, and only call Dispose when you determine you don't need the object anymore.

Curiously you link to the XY problem, and you're falling into that exact trap: your actual problem is that you have memory leaks (I assume, but you didn't explain), and you're asking about your attempted solution (dispose everything).

But that's the wrong solution to the problem. You will run into a world of pain with this solution (you've already found one, and if you go ahead with keeping handles around you'll end up in a much worse place: how to solve crashes instead of how to solve memory leaks).

The correct solution is:

  1. Diagnose (and profile) to understand what's really happening (with the memory leaks).
  2. Only dispose objects that you know are no longer needed (and that the GC couldn't already determine isn't needed). You want to dispose as little as possible (it makes your code easier to maintain), and you need to do step 1 first in order to know those objects.
Rolf Bjarne Kvinge
  • 19,253
  • 2
  • 42
  • 86
  • You're right, but my actual *actual* **actual** problem is that I'm trying to find a consistent way to manage memory *before* I even start the project. I have just completed a Xamarin.Android app where I had memory leaks because I didn't understand how the C# GC interacts with the Java GC (I ended up giving up and calling `GC.Collect()` occasionally). So I'm trying to be extra careful from the beginning of this new project and learn by doing stupid things now instead of learning them too late by the end of the project :P . – imgx64 Jan 13 '16 at 10:47