PDA

View Full Version : UIViewController not released - strange behaviour




namanhams
Jul 28, 2010, 05:16 AM
I have a UIViewController which is pushed onto a UINavigationController.
Inside the view controller, i do downloading some data from internet. It may take a long time.
The problem is that :
If i use NSInvocationOperation to download the data on another thread (which is what i prefer to do), and then i tap the 'back' button to pop the view controller out, the 'dealloc' of the view controller is not called. Only when the downloading finishes, the 'dealloc' is called. This is quite strange to me, as i've read the documentation about UIViewController and there's nothing that can explain this.

Anyone can explain for me ? Thanks in advance.



robbieduncan
Jul 28, 2010, 05:44 AM
Post your code. You must be retaining a reference to the view controller in the operation somewhere...

namanhams
Jul 28, 2010, 05:51 AM
Thank you. You are rite. In the :


NSInvocationOperation operation = [[NSInvocationOperation alloc] initWithTarget:self selector:.......];


'self' is retained. Actually i used it quite many times but never thought that it will retain the target :cool:

North Bronson
Jul 30, 2010, 02:39 AM
I've seen this happen, too. One way around this that might work:

Define a category on UIViewController. Make some new method called categoryCancelQueue (or whatever you want).

Subclass UINavigationController and override popViewControllerAnimated: so that you can grab the view controller being popped. Send categoryCancelQueue to the controller being popped.

In your view controller's implementation of categoryCancelQueue, cancel the operations in the queue. You might even go ahead and try to release the queue (just in case that helps). If you clean everything up, the view controller might release right away once it's popped.

I'm not sure if the NSInvocationOperation will quit right away once it's been cancelled, I know that a custom subclass of NSOperation could be smart enough to stop quickly.

Luke Redpath
Jul 30, 2010, 04:02 AM
That's a lot of work just to cancel an operation.

If you really need to cancel it when the controller is popped, just overridd viewWillDisappear and cancel it there.

Like you say though, there is no guarantee that calling cancel will actually cancel the operation.

Generally speaking, it is recommended that you make use of asynchronous APIs for networking like the async NSURLConnection methods. If you want to push this onto a background thread to avoid runloop latency you can but you will need to write your own concurrent NSOperation subclass and handle the cancelled flag appropriately.

PhoneyDeveloper
Jul 30, 2010, 10:17 AM
This is a design used somewhat frequently in the frameworks. Task objects that take a delegate or target retain that delegate while the task is running. In all cases the task objects have some kind of cancel method. The cancel method both stops the task and causes the delegate to be released. NSURLConnection works like this. One of the Sound player classes (I forget the name) also works like this.

This design leads to a temporary retain-cycle. The retain-cycle is broken by the cancel method, and of course when the task completes.

I ran into problems with NSURLConnection before I understood this issue. Hitting the back button while running a connection ended up with a dangling pointer because I wasn't properly cancelling the connection.