Does any one know when is the best time to stop an NSTimer that is held reference inside of a UIViewController to avoid retain cycle between the timer and the controller?
Here is the question in more details: I have an NSTimer inside of a UIViewController.
During ViewDidLoad of the view controller, I start the timer:
statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateStatus) userInfo: nil repeats: YES];
The above causes the timer to hold a reference to the view controller.
Now I want to release my controller (parent controller releases it for example)
the question is: where can I put the call to [statusTimer invalidate] to force the timer to release the reference to the controller?
I tried putting it in ViewDidUnload, but that does not get fired until the view receives a memory warning, so not a good place. I tried dealloc, but dealloc will never get called as long as the timer is alive (chicken & egg problem).
Any good suggestions?
You can try with
- (void)viewDidDisappear:(BOOL)animated
and then you should validate it again in- (void)viewDidAppear:(BOOL)animated
More here
One way around it is to make the NStimer hold a weak reference to your UIViewController. I created a class that holds a weak reference to your object and forwards the calls to that:
and you use it like this:
Your dealloc method gets called (unlike before) and inside it you just call:
I wrote a "weak reference" class for exactly this reason. It subclasses NSObject, but forwards all methods that NSObject doesn't support to a target object. The timer retains the weakref, but the weakref doesn't retain its target, so there's no retain cycle.
The target calls [weakref clear] and [timer invalidate] or so in dealloc. Icky, isn't it?
(The next obvious thing is to write your own timer class that handles all of this for you.)
invalidate timer inside - (void)viewWillDisappear:(BOOL)animated did work for me
I had exactly the same issue and in the end I decided to override the release method of the View Controller to look for the special case of the retainCount being 2 and my timer running. If the timer wasn't running then this would have caused the release count to drop to zero and then call dealloc.
I prefer this approach because it keeps it simple and encapsulated within the one object, i.e., the View Controller and therefore easier to debug. I don't like, however, mucking about with the retain/release chain but I cannot find a way around this.
Hope this helps and if you do find a better approach would love to hear it too.
Dave
EDIT: Should have been -(oneway void)
You can write this code in dealloc function of view controller
for eg.
this way the reference counter of statustimer will automatically decrement by 1 & also the data on the allocated memory will also erase
also you can write this code in
- (void)viewDidDisappear:(BOOL)animated
function