Would calling removeFromSuperview in a customized UIView as [self removeFromSuperview] correctly remove itself from its super view just like doing [self.customView removeFromSuperview] in its super view?
I've checked and it does seem to do the same but I'd still like to make sure!
Sure. How a UIView instance receives the removeFromSuperview message is irrelevant – it will do exactly the same thing whether it was called from outside or within the instance.
The view will also get deallocated in the exact same way after being removed from the superview, as long as there are no other strong references to it. If you want, you can test it yourself by implementing the dealloc method in your view's subclass, and adding an NSLog or a breakpoint to it.
The only notable exception for when you can call removeFromSuperview is you should never call it from within the view's drawRect: method, as stated in the documentation. Doing so would lead to undefined behaviour.
Related
Is it dealloc or which method? If I setup some code in viewDidLoad, I want to unistall this setup from the pair method of viewDidLoad.. For example viewDidLoad & viewDidDisappear combo is not always clever combination. And sometimes is better to do the setup from viewDidLoad than from viewDidAppear (because that can usually cause flickering)
Starting in iOS 6, views are no longer unloaded by the OS.
You can still manually unload your views when they are not needed by doing self.view = nil; in your code, but in that case, any code you want to run when the view is unloaded can just be put after that line.
There's a UIViewController method -(void)viewDidUnload. I tried putting NSLog("unloaded"); in there to see when the view is unloaded, but nothing was printed to the console.
Where do I put my code, so that before a view unloads I can perform an action?
If you read the viewDidUnload documentation, you see that it's related to low memory conditions and may be called to help with that. There is also a viewWillUnload that get's called before the view is released. It's also related to low memory.
If you're only interested in when the view is no longer seen, there are will/did disappear methods.
Are you using storyboard or not?
Have you tried any of this methods
-(void) viewWillUnload{}
or
-(void)viewWillDisappear:(BOOL)animated{}
If you are using storyboards the one that will that usually performs is viewWillDisappear.
I'm familiar with the delegate pattern and nilling my delegates, especially when doing asynchronous calls which are still in progress when my view controllers disappear. I nil the delegate, and the callback successfully returns on a nil object.
I'm now experimenting with using completion blocks to make my code a little easier to read.
I call a network service from my view controller, and pass a block which updates my UITableView. Under normal circumstances it works fine. However, if I leave the view before it completes, the completion handler block is executed - but the UITableView is now a zombie.
Whats the usual pattern for handling this?
UPDATE WITH CODE SAMPLE
This is an iPad app, I have two view controllers on screen at once, like a split view. One is the detail, and the other is a grid of images. I click an image and it tell the detail to load the info. However, if i click the images too fast before they have chance to do the network call - I have the problems. On changing images the code below is called which counts the favourites of a image....
So here is my dilemma, if I use the code below - it works fine but it leaks in instruments if you switch images before the network responds.
If I remove the __block and pass in self, then it crashes with zombies.
I can't win... I'm sure i'm missing something fundamental about using blocks.
__block UITableView *theTable = [self.table retain];
__block IndexedDictionary *tableData = [self.descriptionKeyValues retain];
FavouritesController *favourites = [Container controllerWithClass:FavouritesController.class];
[favourites countFavouritesForPhoto:self.photo
completion:^(int favesCount) {
[tableData insertObject:[NSString stringWithFormat:#"%i", favesCount]
forKey:#"Favourites:" atIndex:1];
[theTable reloadData];
[tableData release];
[theTable release];
}];
Any tips? Thanks
SECOND UPDATE
I changed the way I loaded the favourites. Instead of the favourites being a singleton, I create an instance on each photo change. By replacing this and killing the old one - the block has nowhere to callback (i guess it doesn't even exist) and my code now just looks like the below, and it appear to be working:
[self.favourites countFavouritesForPhoto:self.photo
completion:^(int favesCount) {
[self.descriptionKeyValues insertObject:[NSString stringWithFormat:#"%i", favesCount]
forKey:#"Favourites:" atIndex:1];
[self.table reloadData];
}];
It doesn't leak, and doesn't appear to be crashing either.
I recommend you test that the tableview is not nil at the start of the block. It sounds like the tableview is properly discarded when its parent view goes off-screen, so after that point, no tableview operations are valid.
Retaining the UITableView within the block is a bad idea, because datasource/tableview updates can result in implicit method calls and notifications that will not be relevant if the tableview is not on-screen.
Block will retain any object that it references, except for those annotated with __block. If you want not to execute completion blocks at all, just make some property like isCancelled and check whether it is YES before calling completion block.
So you have a background operation which has to call back another object after it finishes and the object can be destroyed in the meantime. The crashes you describe happen when you have non retained references. The problem as you see is that the referred object goes away and the pointer is invalid. Usually, what you do is unregister the delegate inside the dealloc method so that the background task continues, and whenever it is ready to communicate the results back it says "Shoot, my callback object is nil", and at least it doesn't crash.
Still, handling manually weak references is tedious and error prone. You can forget to nil a delegate inside a dealloc method and it may go without notice for months before you encounter a situation where the code crashes.
If you are targeting iOS 5.0 I would read up upon ARC and the weak references it provides. If you don't want to use ARC, or need to target pre 5.x devices, I would recommend using zeroing weak reference libraries like MAZeroingWeakRef which work also for 3.x devices.
With either ARC's weak references or MAZeroingWeakRef, you would implement the background task with one of these fancy weak reference objects pointing back to your table. Now if the pointed object goes away, the weak pointer will nil itself and your background task won't crash.
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.
Hi I want to release my fetchedResultsController.
I was wondering why is viewdidunload not called when i push back button on navigation based application.or i should release it somewhere else?
thanks for help
-viewDidUnload is only guaranteed to be called when the view is purged from memory, and the UIKit framework might be hanging on to it in order to present the view quickly if the user goes back there. To deterministically release your fetched result controller when the view disappears, use -viewWillDisappear: or -viewDidDisappear:.
If you think that you're having leaks because viewDidLoad isn't called, than check your controller.view removeFromSuperView calls and ensure that you're using removeFromParentViewController. Instead of just removing the view from superview remove your viewController from its parentController.
I'm seeing something strange happening in my case: dealloc is called but viewDidUnload don't.
But I think I can live with that for memory management purposes because all my strong properties will be deallocated at that time (I'm using ARC).
In your case I think you should check also for dealloc being called and release your fetchedResultsController there.
you can call it yourself from -dealloc.