Appropriate to delete files or close DB connection in dealloc? - objective-c

I know that dealloc is called when an object's retain count reaches zero and that iVars should be released therein, but I am wondering if it is also an appropriate spot to delete temporary files or close database connections.
Specifically, I have a subclass of UIViewController that creates a database connection in -viewDidLoad and through user interaction, temporary files can be created. I would like to close the DB connection and delete the temporary files (if they exist) when the aforementioned controller gets popped of the navigation stack. Should I do so in dealloc?
My first thought was to do this DB and file clean up in -viewDidUnload, but I now know that this method is only called when a memory warning is issued by the OS. Another thought was to put it in -viewDidDisappear:animated but the issue with that approach is that the another view may go on top of the one controlled by my view controller. In that scenario, I do not want to close the DB connection or clean up the temp files.
If dealloc is not the appropriate spot (this is my gut feeling), where should this type of clean up be done? I would kind of hate to force the parent of my view controller to have to call a method in response to its child getting popped off the navigation stack.

The Apple guide to memory management says, No.
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW13
In short, don't use dealloc to manage resources.

You can do so in dealloc, or if you need the files around during app lifecycle, on your app delegate's applicationWillTerminate:. YMMV.

Do not try to do this in the dealloc method of your view controller.
What would happen if the view controller gets retained somewhere you're not expecting it? The dealloc method may not get fired, and you clean up never occurs. Maybe that's not the case in the code you're writing now, but something could change in the future.
Is there any specific reason you want to tie the deletion of files and closing of the DB connection to popping off the view controller? If not, perhaps you could do this immediately your query has completed, or it may make sense to open the DB connection on startup/foreground, and then close it on termination/backgrounding.
If you must tie it to view controller being popped off the nav stack, then you could call your clean-up method from viewDidDisappear:

Related

Observers remaining in dispatch table after object removed

Kind of a newbie question, so forgive me if I'm missing some basic concepts...
I have a view controller within a window, which contains multiple NSTableViews, each of which having a variety of associated observers added via addObserver. These work fine and as expected, with notifications going to each of the correct table views. However, if I close the window, then open a new window (of the same type), posted notifications are being sent to the table views of the window that was previously closed.
I was under the impression that as of macOS 10.11 observers did not have to be explicitly removed, which I would assume would happen when the original window is closed... UNLESS I'm missing something fundamental about closing windows. At the moment, I don't do anything special when the user closes a window, and the window just vanished from the screen. Do the views created in my viewDidLoad method live on even after the window is closed? Or no I need to explicitly dispose of these views in a method such as viewWIllDisappear?
Thanks!
Even when object you added as observer is disposed the observer is not. According to official documentation you have to pair each addObserver with corresponding removeObserver. This is true and for NotificationCenter and for KVO. By the way adding object as observer does not increase its owners, so under correct memory management left observer result in run-time crash - that is why needed paired removeObserver (if there is no crash in such situation it means there is leak).
The place where to do this depends on usage. If you add observer in viewWillAppear then it is better to remove it in viewWillDisappear, if you add on creation then remove should be done in deinit

Cancelling NSURLConnection when leaving a view

Do I need to cancel the opened connections (NSURLConnection) when I leave the view?
I'd do that in viewWillDisappear or viewDidDisappear but I don't know whether I actually need to do that.
If you're using ARC, there's a good chance your NSURLConnection objects (assuming they are instance variables or that you're holding onto them in memory somehow) will get magically released when the view controller goes away.
But to be sure, and to be nice, you should cancel the open connections. Doing the NSURLConnection object "cancel" in either "viewWillDisappear" or "viewDidDisappear" should work well.

UIViewController does not release its views

I was trying to fix a memory leak in my application and stumbled upon a very interesting thing. Now i'm not sure if there's a bug that i made somewhere or simply misuse of the technology so i'll try to get things clear with your help. Here's what happens:
i create a custom uiviewcontroller that loads its view from nib file
i release the controller
controller's dealloc method gets called where i release a custom view that i've specifically added to the view hierarchy as an outlet (i made a retainable property out of it). It has a dealloc method with a call to nslog.
the main view in the nib file (connected to controller's view outlet) is also a subclass of a uiview which also has a call to nslog in its dealloc
The problem is - even though the uiviewcontroller's dealloc is getting called, neither the main view nor the child (the one with outlet) gets released (their NSLogs don't fire).
Is it normal that this happens? Maybe iOS doesn't release the views right away? Or should i start looking for bugs in the code? If so - what could be the most probable causes?
Thanks for reading
The problem with late night debugging is that you don't consider even the simplest angles. Since i like to know how things work and do everything from scratch, i've created my own system for switching view controllers. The problem was that even though i used to deallocate the view controller when needed, i forgot to remove it from superview, thus having one more retain too many. Now there's a leak somewhere else, but i'm sure i'll solve it myself. Thanks for your comments.

ASIHTTPRequest popViewControllerAnimated: => delegate EXEC_BAD_ACCESS

I set the view controller to be the delegate of a local variable ASIHTTPFormDataRequest request.
But, tapping "Back" before the request has finished, pops and deallocates the view controller. So, when the request completes and sends the message -requestDidFinish: to the now nonexistent delegate, the app crashes with an EXEC_BAD_ACECESS exception.
How do I fix this crash?
One way I could think of solving this is to set the delegate to nil immediately after the navigation controller pops it. But, if that's the solution, how do I do that? (ARC's weak references would be sweet right now.)
Another way I can think of is to make request an instance variable of the view controller and call [request clearDelegatesAndCancel]; [request release]; in the view controller's dealloc method. This approach is outlined in ASIHTTPRequest Example Code, but I've been advised it's best to make requests local variables instead of instance variables. And, this particular view controller is a settings table view controller and has 13 switches. For automatic saving to the server, each switch creates & sends a new request each time it's toggled. If I made ivars, I'd have to make 13. That's a lot of code!
Thoughts? Ideas?
I think the first question is: What do you want to happen if the user presses back after pressing a switch? ie. Should the http request be cancelled, or is it important that the request does get to the server? I'll assume for now that you do want to cancel them, as that seems to be implied in your question.
I've been advised it's best to make
requests local variables instead of
instance variables
I'm not sure if that was good advice - you almost always want requests to not be local variables so you can cope with cases like this.
For your case, you could consider using an NSOperationQueue.
Rough steps to do this would be:
Create an NSOperationQueue in your view controller init.
When you want to make a http request, add it to the ASIHTTPRequest queue instead of call startAsynchronous
In dealloc, iterate the objects in the queue, calling [request clearDelegatesAndCancel]; for each one, and then release the queue.
That should solve the crash without needing 13 ivars!
I solved this by retaining the request delegate like NSURLConnection retains its delegate.

What am I doing wrong with NSManagedObjectContext dependency injection?

I am trying to use NSManagedObjectContext dependency injection as recommended by Marcus Zarra -- I'm creating an M.O.C. in my AppDelegate and passing it as a retained property to each of my view controllers.
Generally this seems to work well, but in a modal table view controller that presents data via an NSFetchedResultsController, I only see what was in the database when the app was launched. That is, if the user adds data at runtime, it gets added correctly to the database, but does not appear when the modal ViewController is opened and the NSFetchedResultsController is created (using the injected NSManagedObjectContext). However, if I close the app and restart, then open the modal view controller, I do see the data added in the previous session.
Do I have to refresh the M.O.C. in some way prior to creating the NSFetchedResultsController? I am absolutely sure that the modal view controller and the NSFetchedResultsController are being created, and the fetch is being executed, AFTER the new user data has been entered.
To start, you should log the moc in both app delegate and your view controller to confirm that the moc in both places has the same address and is therefore the same object.
If it is, then most likely you've got an issue with the FRC's cache. Set the cache to nil and/or refresh the cache and see if that resolves it.