As I understand it, we need to hold references to our Cocoa objects when dealing with them in MonoTouch. The reason for this is that the ObjC runtime might still hold references to the objects, and if we have no "MonoTouch references" on them, they could be garbage collected, which results in a EXC_BAD_ACCESS as soon as the ObjC runtime tries to access them.
Say, we have two UIViewController subclasses, VC1 and VC2. If the user clicks on a button on VC1, the UI navigates to VC2, and the user can navigate back and forth. If I create a new instance of VC2 every time the user navigates to it, then the references to the old instances get lost, so they're garbage collected and the app crashes the next time a didReceiveMemoryWarning is propagated to the UIViewControllers.
How can I release the old references, so I don't have to use the same instance of VC2 every time? Dispose seemed to not be enough.
As I understand it, we need to hold references to our Cocoa objects when dealing with them in MonoTouch.
Not quite. MonoTouch managed instances will keep a reference to native instances. As long as the managed instance exists the native instance will be alive (since they are reference counted and MonoTouch won't release it's reference).
IOW your need to hold references to the MonoTouch managed instances as long as their native part are required.
The reason for this is that the ObjC runtime might still hold references to the objects ... they could be garbage collected,
Native (Objective C) instances are reference counted, not garbage collected. Native instances won't be released until their reference count reach 0 (which won't happen while an associated managed instance exists);
Also native instances can hold references to other native instances. Not every native instances have a corresponding managed instance.
which results in a EXC_BAD_ACCESS as soon as the ObjC runtime tries to access them.
That won't happen, at least not this way. OTOH it's hard to tell you what's happening in your case (without seeing the code and/or the crashes).
I suspect you're disposing (manually or not) your managed instances before they have completed their jobs. Here's a simplified of what could happen:
you create a managed MT.X instance (e.g. an UIView);
this creates and reference a native X (native reference count == 1);
you override an event (or add a delegate...) `ViewWillUnload' on MT.X (which also exists natively);
you assign the MT.X instance to another (managed) instance, e.g. an UIViewController;
the native UIViewController will add a reference to the native X (native reference count == 2);
application executes happilly...
you stop having a reference to the MT.X instance (e.g. set the variable to null or a different instance);
since there's no reference to MT.X anymore the Garbage Collector will dispose the managed instance, calling Dispose which will reduce the reference to native X (native reference count == 1). But the native instance won't be freed since it's still referenced (not 0) by the view controller;
the UIViewController does something that triggers, natively, X.ViewWillUnload (e.g. it tries to load a new UIView);
since X still exists natively (ref count == 1) it will call it's ViewWillUnload which will try to go back to the managed instance... that was disposed.
The solution to this problem is to ensure ensure you're not disposing managed instance until their native part have completed their jobs.
I've the same situation in my app and GC collects objects correctly. In other words, I never experienced a problem simply nulling reference to a VC and letting GC do the rest.
However, I DID have problems when called for Dispose method as you do. It seems we shouldn't do this manually. Instead we should wait for GC to collect objects and free its resources. Base NSObject class has a call to Dispose in its finalizer, so all unmanaged resources will be freed upon object is collected.
You may also call for GC.Collect in some of the root VC's DidReceiveMemoryWarning method.
Related
I am debugging the my Cocoa application and noticed using the Instruments.app allocation profile that the model object graph is not deallocating as I expect. Basically when I remove a root model object from the my NSDocument I was expecting the whole object graph for that object to be deallocated. That doesn't happen, which means that there is a strong reference to my root model object somewhere else in the application.
Is it possible to get a list of object which have a reference to a specific object in Cocoa either programmatically or using Instruments.app? If I could know where the strong reference is held this would help with debugging this problem.
I found this similar question, How to get the reference count of an NSObject?, but this simply says which how many references there are, not which objects hold the references.
Not in this way. The only information that is stored inside of a running process is the number of retains on an object (number of times "retain" has been called net the number of times "release" has been called). This is not the same as the number of references (number of "strong" pointers to the memory). Most memory locations do not have a side table of things that point to them in Cocoa.
In Instruments, you can turn on "record reference counts" and see everywhere the retain count is increased or decreased. See Instruments Allocations track alloc and dealloc of objects of user defined classes for a good explanation of how to do that. This won't tell you where you've made your mistake, but it will tell you where the retains are occurring.
Is there any point to using retain on a singleton? I believe the whole point of using the singleton pattern is to keep one global object to access from various classes. What would be a case to use retain on such an object?
Generally, the implementation of retain in a singleton class returns self (not singleton instance) like below:
-(id)retain
{
return self;
}
I recently went through some open source code, and the author repeatedly retained the singleton
object = [[SingletonClass shareObject] retain]
and released it in dealloc.
So when I tried to build this project, it worked at first, then crashed when it attempted to access variables on singleton object later.
What would happen exactly, if I retain a singleton object and attempt to access it?
Just because it's a singleton doesn't mean its lifetime is necessarily the lifetime of the process. For example, you might have some singleton that obtains a resource. But until you need that resource, there's no point in creating it. Likewise, you might know that all instances are done with that resource, so why keep it around? An easy way to keep track of whether a singleton needs to continue to exist is its retain count.
For example, you might have a singleton that represents the video camera built-in to a user's device. There might be different parts of your application that need to access the camera. But it might also be possible to use your app without the camera, or the workflow may dictate that the camera is turned off at some point (for privacy, or whatever). So you don't allocate the singleton until the user initiates an action that starts camera use. They may do several actions with the camera, such as take a picture, scan a QR code, record some video, etc. Then they may end all of those actions and need the memory taken by the camera freed up (especially on a mobile device). So they end those actions. If each camera-related actions retained the camera singleton, then each released it when they were done, you could free up the memory and other resources used by the camera, even though it's still a singleton.
Consistency. Make a point of always retaining objects that you keep references to, even if they're singletons, and you won't make mistakes down the road when you forget to retain objects that reference counts do matter for.
Never hold on to a singleton. There is no guarantee that the underlying library/class/manager doesn't replace that singleton with a new object in the application's lifetime. The point of a singleton access static method is for the current valid singleton to be available at any time to any caller.
Singletons are written by anyone and there is no guarantee that the singleton is not switched. The only guarantee is that a specific class will only have one existing instance at any time.
If you retain a singleton at some point the object you retained could be invalid or even worse, be completely different from the one being held to by the class singleton() method.
I started objective-c and iOS a couple of weeks ago (worth bearing in mind), and I apologise in advance for the awful diagram!!
The above diagram shows the structure of my calls to a webservice. Thin arrows denote an object creating another object, whereas thick arrows denote an object holding a strong (retained) reference to the pointed-to object.
I believe that this contains what is called a "circular reference" and will create problems when it comes to deallocating the objects.
I understand that the easy answer would be to replace some of the strong references to weak ones, which I'd love to do, except my project is also targeting iOS 3.2 (not my decision - I can't really change this fact!). So, I think I'm right in saying that I have to use __unsafe_unretained instead, but I'm quite worried about the fact that these won't auto-zero, as I'll end up with EXC_BAD_ACCESS problems when objects get deallocated...
So my problem is firstly that I have circular references. To solve, I would have to use __unsafe_unretained, which leads to my second problem: How to correctly manage these?
A question that might be related is: How does NSURLConnection manage it's strong references? I have heard from various sources that it retains its delegate? So...if I retain an NSURLConnection, (and am also its delegate) and it retains me, this would also be a circular reference, no? How does it get around my problem?
Any advice is very welcome!
Regards,
Nick
When a parent has a reference to a child object, it should use a strong reference. When a child has a reference to it's parent object, it should use a weak reference, aka unsafe_unretained.
By convention, delegate relationships in iOS are usually weak references, so you'll find that most delegate properties on Apple's own classes are declared as unsafe_unretained.
So your controller retains the services that it is using, but the services only weakly link back to the controller. That way, if the controller is released, the whole lot can be safely disposed of without any circular references.
The danger with this is that if the web service is doing some long-running task, and the controller gets released before it has finished, the service is left with a dangling pointer to it's now-deallocated delegate. If it tries to send a message to the delegate, such as "I have finished" it will crash.
There are a few approaches to help solve this (they aren't mutually exclusive - you should try to do them all whenever possible):
1) Always set the delegate properties of your services to nil in your controller's dealloc method. This ensures that when the controller is released, the delegate references to it are set to nil (sort of a crude, manual equivalent of what ARC's weak references do automatically).
2) When creating your own service classes that have delegates, make them retain their delegate while they are running and then release the delegate when they are done. That way the delegate object can't get deallocated while the service is still sending it messages, but it will still get released once the service has finished (NSTimer's and NSURLConnections both work this way - they retain their delegate while they are running and release it when they are done).
3) Try not to have long-running services owned by something transient like a view controller. Consider creating singleton objects (shared static object instances) that own your services, that way the service can do it's job in the background regardless of what's going on in the view layer. The controller can still call the service, but doesn't own it - the service is owned by a static object that will exist for the duration that the app is running, and so there's no risk of leaks or premature releases. The service can communicate with the controller via NSNotifications instead of delegate calls, so there is no need for it to have a reference to an object that may vanish. NSNotifications are a great way to communicate between multiple classes without creating circular references.
All of your questions and concerns are correct, and this problem with the previous use of assign (now better named __unsafe_unretained) is why Apple developed auto-zeroing for weak. But we've dealt reasonably safely with assign delegates for many years, so as you suspect, there are ways to do it.
First, as a matter of practice, you should always clear yourself as the delegate when your release an object you were delegate for. Pre-ARC, this was traditionally done in dealloc:
- (void)dealloc {
[tableView_ setDelegate:nil];
[tableView_ release];
tableView_ = nil;
}
You should still include that setDelegate:nil in your dealloc if delegate is __unsafe_unretained. This will address the most common form of the problem (when the delegate is deallocated before the delegating object).
Regarding NSURLConnection, you are also correct that it retains its delegate. This is ok because it has a lifespan typically much shorter than its delegate (versus a table view delegate which almost always has the same lifespan as the table view). See " How to work around/handle delegation EXC_BAD_ACCESS errors? Obj C " for more discussion on this in a pre-ARC context (the same concepts apply in the new world of strong/weak).
I have tried using the leaks tool, and "analyze" etc to find the leak, but it can't find it. Using allocations I can determine the objects which are not being released.
I have noticed (by adding debugging statements in the dealloc method), that dealloc is not called for these objects.
How can I determine which objects are holding references to these objects and preventing them from being released?
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the picker to run, stop recording, search for there ivar (datePickerView), drill down and you will be able to see where all retains, releases and autoreleases occurred.
The analyze tool was unable to detect the problem. Using the allocations tool to capture all the reference counts was a start, but there were so many classes I didn't recognize, or access directly, I was not able to track down the problem using this method. Instead, I made a list of the classes that I was directly responsible for, and investigated each of them line by line till I found the problems. The cause was that I used some third party libraries which didn't decrement the retain count of some of my objects as expected. I guess in this case, following better software engineering principles / design patterns, and having thorough code reviews may have caught the problem earlier.
I would start by building and analyzing the project ( Shift Command B in the IDE ).
You can overload retain/release/autorelease implementations in problematic classes (if it's an SDK class, it's possible to use a category) and set breakpoint there. Your breakpoint will be hit each time something retains your object.
I want to cache the instances of a certain class. The class keeps a dictionary of all its instances and when somebody requests a new instance, the class tries to satisfy the request from the cache first. There is a small problem with memory management though: The dictionary cache retains the inserted objects, so that they never get deallocated. I do want them to get deallocated, so that I had to overload the release method and when the retain count drops to one, I can remove the instance from cache and let it get deallocated.
This works, but I am not comfortable mucking around the release method and find the solution overly complicated. I thought I could use some hashing class that does not retain the objects it stores. Is there such? The idea is that when the last user of a certain instance releases it, the instance would automatically disappear from the cache.
NSHashTable seems to be what I am looking for, but the documentation talks about “supporting weak relationships in a garbage-collected environment.” Does it also work without garbage collection?
Clarification: I cannot afford to keep the instances in memory unless somebody really needs them, that is why I want to purge the instance from the cache when the last “real” user releases it.
Better solution: This was on the iPhone, I wanted to cache some textures and on the other hand I wanted to free them from memory as soon as the last real holder released them. The easier way to code this is through another class (let’s call it TextureManager). This class manages the texture instances and caches them, so that subsequent calls for texture with the same name are served from the cache. There is no need to purge the cache immediately as the last user releases the texture. We can simply keep the texture cached in memory and when the device gets short on memory, we receive the low memory warning and can purge the cache. This is a better solution, because the caching stuff does not pollute the Texture class, we do not have to mess with release and there is even a higher chance for cache hits. The TextureManager can be abstracted into a ResourceManager, so that it can cache other data, not only textures.
Yes, you can use an NSHashTable to build what is essentially a non-retaining dictionary. Alternatively, you can call CFDictionaryCreate with NULL for release and retain callbacks. You can then simply typecast the result to a NSDictionary thanks to tollfree bridging, and use it just like a normal NSDictionary except for not fiddling with retain counts.
If you do this the dictionary will not automatically zero the reference, you will need to make sure to remove it when you dealloc an instance.
What you want is a zeroing weak reference (it's not a "Graal of cache managing algorithms", it's a well known pattern). The problem is that Objective C provides you with zeroing weak references only when running with garbage collection, not in manual memory managed programs. And the iPhone does not provide garbage collection (yet).
All the answers so far seem to point you to half-solutions.
Using a non-reataining reference is not sufficient because you will need to zero it out (or remove the entry from the dictionary) when the referenced object is deallocated. However this must be done BEFORE the -dealloc method of that object is called otherwise the very existence of the cache expose you to the risk that the object is resurrected. The way to do this is to dynamically subclass the object when you create the weak reference and, in the dynamically created subclass, override -release to use a lock and -dealloc to zero out the weak reference(s).
This works in general but it fails miserably for toll-free bridged Core Foundation objects. Unfortunately the only solution, if you need to to extend the technique to toll-free bridged objects, requires some hacking and undocumented stuff (see here for code and explanations) and is therefore not usable for iOS or programs that you want to sell on the Mac App Store.
If you need to sell on the Apple stores and must therefore avoid undocumented stuff, your best alternative is to implement locked access to a retaining cache and then scavenge it for references with a current -retainCount value of 1 when you want to release memory. As long as all accesses to the cache are done with the lock held, if you observe a count of 1 while holding the lock you know that there's no-one that can resurrect the object if you remove it from the cache (and therefore release it) before relinquishing the lock.
For iOS you can use UIApplicationDidReceiveMemoryWarningNotification to trigger the scavenging. On the mac you need to implement your own logic: maybe just a periodical check or even simply a periodical scavenging (both solutions would also work on iOS).
I've just implemented this kind of thing by using an NSMutableDictionary and registering for UIApplicationDidReceiveMemoryWarningNotification. On a memory warning I remove anything from the dictionary with a retainCount of 1...
Use [NSValue valueWithNonretainedObject:] to wrap the instance in an NSValue and put that in the dictionary. In the instance dealloc method, remove the corresponding entry from the dictionary. No messing with retain.
My understanding is that you want to implement the Graal of cache managing algorithms: drop items that will no longer be used.
You may want to consider other criteria, such as dropping the least recently requested items.
I think the way I would approach this is to maintain a separate count or a flag somewhere to indicate if the object in the cache is being used or not. You could then check this when you're done with an object, or just run a check every n seconds to see if it needs to be released or not.
I would avoid any solution involving releasing the object before removing it from the dictionary (using NSValue's valueWithNonretainedObject: would be another way to accomplish this). It would just cause you problems in the long run.