Now, this question have partially been asking alot, but none actually considering how (or when) the messages -viewWillDisappear & -viewDidDisappear are being sent. Almost every example use the following design:
[UIView animateWithDuration:0.5
delay:1.0
options: UIViewAnimationCurveEaseOut
animations:^{
yourView.alpha = 0;
}completion:^(BOOL finished){
[yourView removeFromSuperview]; // Called on complete
}];
The problem with this is that these messages will both be sent when de animation ends!
Now, -addSubview can be animated (if put inside the animations-block) which will send the corresponding messages (-viewWillAppear & -viewDidAppear) with correct timedifference. So naturally one would place -removeFromSuperview inside the animations-block. This WILL send the messages correctly, but the view is actually removed instantly making the animation... Well, it won't animate because nothing is left to animate!
Is this intentional from apple and if so, why? How do you do it correctly?
Thanks!
Edit.
Just to clearify what I'm doing:
I got a custom segue, vertically animating a Child-ViewController down from top which works as expected with the following code:
-(void)perform{
UIViewController *srcVC = (UIViewController *) self.sourceViewController;
UIViewController *destVC = (UIViewController *) self.destinationViewController;
destVC.view.transform = CGAffineTransformMakeTranslation(0.0f, -destVC.view.frame.size.height);
[srcVC addChildViewController:destVC];
[UIView animateWithDuration:0.5f
animations:^{
destVC.view.transform = CGAffineTransformMakeTranslation(0.0f, 0.0f);
[srcVC.view addSubview:destVC.view];
}
completion:^(BOOL finished){
[destVC didMoveToParentViewController:srcVC];
}];
}
Here it will happen in the following order (thanks to -addSubview being inside the animations-block):
Add childView (will automatically invoke -willMoveToParentViewController)
-addSubview will invoke -viewWillAppear
When the animation finishes, -addSubview will invoke -viewDidAppear
Manually invoke -didMoveToParentViewController inside the completion-block
Above is the exact expected behavior (just like the built-in transitions behave).
With the following code to do the above segue but backwards (with an unwindSegue):
-(void)perform{
UIViewController *srcVC = (UIViewController *) self.sourceViewController;
srcVC.view.transform = CGAffineTransformMakeTranslation(0.0f, 0.0f);
[srcVC willMoveToParentViewController:nil];
[UIView animateWithDuration:5.5f
animations:^{
srcVC.view.transform = CGAffineTransformMakeTranslation(0.0f, -srcVC.view.frame.size.height);
}
completion:^(BOOL finished){
[srcVC.view removeFromSuperview]; // This can be done inside the animations-block, but will actually remove the view at the same time ´-viewWillDisappear´ is invoked, making no sense!
[srcVC removeFromParentViewController];
}];
}
the flow will be like this:
Manually invoke -willMoveToParentView:nil to notify that it will be removed
When the animation finishes, both -viewWillDisappear & -viewDidDisappear will be invoked simultaneously (wrong!) and -removeFromParentViewController will automatically invoke -didMoveToParentViewController:nil.
And if I now move -removeFromSuperview in to the animations-block, the events will be sent correctly but the view is removed when the animation starts instead of when the animation finishes (this is the part that makes no sense, following how -addSubview behaves).
Your question is about removing view controller, because, viewWillDisappear and viewDidDisappear are method of view controller.
viewWillDisappear: will be called from completion block, not earlier, because this is the place where you said that you want to remove subview from main view.
If you want to remove some property before that point, then in child controller override willMoveToParentViewController: method. This method will be called before animation block.
Here's code example:
//Prepare view for removeing.
[self.childViewController willMoveToParentViewController:nil];
[UIView animateWithDuration:0.5
delay:1.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
self.childViewController.view.alpha = 0;
}completion:^(BOOL finished){
[self.childViewController.view removeFromSuperview];
[self.childViewController didMoveToParentViewController:self];
}];
So, the flow will be:
First willMoveToParentViewController: with nil parameter will be called
Animation block will start and view will set it's alpha property to 0
When animation finish, completion block will start to execute...
[self.childViewController.view removeFromSuperview]; will be called first
Then viewWillDissapear: in childViewController will be called
Then [self.childViewController didMoveToParentViewController:self];
And at the end viewDidDissapear: in childViewController will execute.
Pre request for this flow is that you embed childViewController with code like this:
[self addChildViewController:self.childViewController];
[self.view addSubview:self.childViewController.view];
[self.childViewController didMoveToParentViewController:self];
Related
I have a parent UIView and an UITextView as one of the subviews.
And I created a button to dismiss the parent UIView like this:
-(void)cancelButtonPressed:(UIButton *)sender
{
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.frame = CGRectZero;
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
}
}];
}
I can tell that the parent UIView didn't get released because if I typed some text into the UITextView and dismissed it, when I opened the UIView again, instead of a blank UITextView, the SAME text is in it again.
I checked the Leaks tool but I didn't see any leaking. So I'm guessing if I have some kind of retain cycle or what.
UPDATE:I have another object (which is the AppDelegate) who is holding the UIView's instance: _myView as a global variable like this:
_myView = [[MyView alloc] init];
_myView.nameLabel.text = _user.screen_name;
[_window addSubview:_myView];
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
_myView.frame = CGRectZero;
} completion:nil];
But in order to avoid retain cycle, should I create a weak self like this: __weak MyView *weakSelf and in the animation block do this: [weakSelf removeFromSuperview]?
I've also tried calling removeFromSuperview on the view itself, and it doesn't result in the view being released.
If you want to release the view, then go with an approach that uses a delegate. That way, you will be able to call removeFromSuperview on the view, once the animation is complete, and set it to nil. This has worked for me in the past.
So, you can add a method to the view class that you want to animate closed, where you will do the animation. Set your view controller as a delegate to your view, and call some method on the delegate, from the completion block of that animation.
You can create your own protocol for this. If you keep it general enough, and focus only on animation callbacks, you can reuse the protocol in all your view controllers.
Memory management and logic are independent things. A memory leak will never change the behavior of your program. Behavior like displaying something is controlled by what you tell it to display. If it displays the same thing as before, then you must be giving it the same thing to display somehow. Even if you somehow leaked the original thing, if you pass a new thing for it to display, it will display that thing. So look at your logic. Memory management has nothing to do with what you're seeing.
I have a problem :D.
I'm currently using a SplitViewController. At the start I want to hide the TableViewController in the MasterView. So i decided to add a SubView in the Storyboard into the tableView, where a little label will be shown.
So after I make my choice in the DetailView and click the Button I want to hide the subView and want to show the tableView. That all with animations.
So here is my Code:
In the TestTableViewController.m
-(void)AnimateView{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.1];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
fixedView.frame=CGRectMake(-500, 0,0,0);
[UIView commitAnimations];
NSLog(#"test");
And in the TestDetailViewController.m
- (IBAction)attractionButton:(UIButton *)sender
{
TestTableViewController *testTableViewController = [[TestTableViewController alloc]init];
[testTableViewController AnimateView];
}
I get the NSLog "test" but the Animation is not working.
fixedView is my Subview and I drag it to the header file so it's an IBOutlet.
Thank you so far.
So you seem to instantiate a new ViewController and trying to perform this animation straight away:
TestTableViewController *testTableViewController = [[TestTableViewController alloc]init];
[testTableViewController AnimateView];
The problem is that you don't even present that view controller (its view is not on screen anywhere) so it's normal you don't see any animation.
From my understanding you already have another instance of this view controller presented on screen (am I right?) - so that is the one that you need to use. Pass its pointer to TestDetailViewController in some way (e.g. a property) and then use that object to call your animation method.
PS. I would recommend naming all your methods starting with a lower case letter ;)
The problem is, you are not referencing the same master view controller in your details view controller.
You are creating another one in your IBAction.
In order to get a hold of your (the "original" one) master view controller, do this in your detail view controller:
Create a ivar:
TestTableViewController *masterViewController;
And then to reference it:
masterViewController = (TestTableViewController*)[[[self.splitViewController.viewControllers lastObject] viewControllers] objectAtIndex:0];
For example:
- (IBAction)attractionButton:(UIButton *)sender
{
masterViewController = (TestTableViewController*)[[[self.splitViewController.viewControllers lastObject] viewControllers] objectAtIndex:0];
[masterViewController AnimateView];
}
And finally in your AnimateView method, make change to the following:
[UIView animateWithDuration:0.1f animations:^
{
fixedView.frame = CGRectMake(-500, 0, 0, 0);
}
completion:nil];
Hope this helps.
What you could try is this:
[UIView animateWithDuration:0.15f animations:^{
fixedView.frame=CGRectMake(-500, 0,0,0);
}completion:^(BOOL finished){
}];
Are you sure you can call [UIView beginAnimations: ....] without a first argument?
How can you use Auto Layout with the UIViewController container transition method:
-(void)transitionFromViewController:(UIViewController *)fromViewController
toViewController:(UIViewController *)toViewController
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion;
Traditionally, using Springs/Struts, you set the initial frames (just before calling this method) and set up the final frames in the animation block you pass to the method.
That method does the work of adding the view to the view hierarchy and running the animations for you.
The problem is that you we can't add initial constraints in the same spot (before the method call) because the view has not yet been added to the view hierarchy.
Any ideas how I can use this method along with Auto Layout?
Below is an example (Thank you cocoanetics) of doing this using Springs/Struts (frames)
http://www.cocoanetics.com/2012/04/containing-viewcontrollers
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
// XXX We can't add constraints here because the view is not yet in the view hierarchy
// animation setup
toViewController.view.frame = _containerView.bounds;
toViewController.view.autoresizingMask = _containerView.autoresizingMask;
// notify
[fromViewController willMoveToParentViewController:nil];
[self addChildViewController:toViewController];
// transition
[self transitionFromViewController:fromViewController
toViewController:toViewController
duration:1.0
options:UIViewAnimationOptionTransitionCurlDown
animations:^{
}
completion:^(BOOL finished) {
[toViewController didMoveToParentViewController:self];
[fromViewController removeFromParentViewController];
}];
}
Starting to think the utility method
transitionFromViewController:toViewController:duration:options:animations:completion can not be made to work cleanly with Auto Layout.
For now I've replaced my use of this method with calls to each of the "lower level" containment methods directly. It is a bit more code but seems to give greater control.
It looks like this:
- (void) performTransitionFromViewController:(UIViewController*)fromVc toViewController:(UIViewController*)toVc {
[fromVc willMoveToParentViewController:nil];
[self addChildViewController:toVc];
UIView *toView = toVc.view;
UIView *fromView = fromVc.view;
[self.containerView addSubview:toView];
// TODO: set initial layout constraints here
[self.containerView layoutIfNeeded];
[UIView animateWithDuration:.25
delay:0
options:0
animations:^{
// TODO: set final layout constraints here
[self.containerView layoutIfNeeded];
} completion:^(BOOL finished) {
[toVc didMoveToParentViewController:self];
[fromView removeFromSuperview];
[fromVc removeFromParentViewController];
}];
}
The real solution seems to be to set up your constraints in the animation block of transitionFromViewController:toViewController:duration:options:animations:.
[self transitionFromViewController:fromViewController
toViewController:toViewController
duration:1.0
options:UIViewAnimationOptionTransitionCurlDown
animations:^{
// SET UP CONSTRAINTS HERE
}
completion:^(BOOL finished) {
[toViewController didMoveToParentViewController:self];
[fromViewController removeFromParentViewController];
}];
There are two solutions depending on whether you simply need to position the view via auto layout (easy) vs. needing to animate auto layout constraint changes (harder).
TL;DR version
If you only need to position a view via auto layout, you can use the -[UIViewController transitionFromViewController:toViewController:duration:options:animations:completion:] method and install the constraints in the animation block.
If you need to animate auto layout constraint changes, you must use a generic +[UIView animateWithDuration:delay:options:animations:completion:] call and add the child controller regularly.
Solution 1: Position a view via Auto Layout
Let's tackle the first, easy case first. In this scenario, the view should be positioned via auto layout so that changes to the status bar height (e.g. via choosing Toggle In-Call Status Bar), among other things, will not push things off the screen.
For reference, here is Apple's official code regarding the transition from one view controller to another:
- (void) cycleFromViewController: (UIViewController*) oldC
toViewController: (UIViewController*) newC
{
[oldC willMoveToParentViewController:nil]; // 1
[self addChildViewController:newC];
newC.view.frame = [self newViewStartFrame]; // 2
CGRect endFrame = [self oldViewEndFrame];
[self transitionFromViewController: oldC toViewController: newC // 3
duration: 0.25 options:0
animations:^{
newC.view.frame = oldC.view.frame; // 4
oldC.view.frame = endFrame;
}
completion:^(BOOL finished) {
[oldC removeFromParentViewController]; // 5
[newC didMoveToParentViewController:self];
}];
}
Rather than using frames as in the example above, we must add constraints. The question is where to add them. We cannot add them at marker (2) above, since newC.view is not installed in the view hierarchy. It is only installed the moment we call transitionFromViewController... (3). That means we can either install the constraints right after the call to transitionFromViewController, or we can do it as the first line in the animation block. Both should work. If you want to do it at the earliest time, then putting it in the animation block is the way to go. More on the order of how these blocks are called will be discussed below.
In summary, for just positioning via auto layout, use a template such as:
- (void)cycleFromViewController:(UIViewController *)oldViewController
toViewController:(UIViewController *)newViewController
{
[oldViewController willMoveToParentViewController:nil];
[self addChildViewController:newViewController];
newViewController.view.alpha = 0;
[self transitionFromViewController:oldViewController
toViewController:newViewController
duration:0.25
options:0
animations:^{
newViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
// create constraints for newViewController.view here
newViewController.view.alpha = 1;
}
completion:^(BOOL finished) {
[oldViewController removeFromParentViewController];
[newViewController didMoveToParentViewController:self];
}];
// or create constraints right here
}
Solution 2: Animating constraint changes
Animating constraint changes is not as simple, because we are not given a callback between when the view is attached to the hierarchy and when the animation block is called via the transitionFromViewController... method.
For reference, here is the standard way of adding/removing a child view controller:
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.frame = [self frameForContentController]; // 2
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self]; // 3
}
- (void) hideContentController: (UIViewController*) content
{
[content willMoveToParentViewController:nil]; // 1
[content.view removeFromSuperview]; // 2
[content removeFromParentViewController]; // 3
}
By comparing these two methods and the original cycleFromViewController: posted above, we see that transitionFromViewController takes care of two things for us:
[self.view addSubview:self.currentClientView];
[content.view removeFromSuperview];
By adding some logging (omitted from this post), we can get a good idea of when these methods are called.
After doing so, it appears that the method is implemented in a manner similar to the following:
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
{
[self.view addSubview:toViewController.view]; // A
animations(); // B
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[fromViewController.view removeFromSuperview];
completion(YES);
});
}
Now it is clear to see why it's not possible to use transitionFromViewController to animate constraint changes. The first time you can initialize constraints is after the view is added (line A). The constraints should be animated in the animations() block (line B), but there is no way to run code between these two lines.
Therefore, we must use a manual animation block, along with the standard method of animating constraint changes:
- (void)cycleFromViewController:(UIViewController *)oldViewController
toViewController:(UIViewController *)newViewController
{
[oldViewController willMoveToParentViewController:nil];
[self addChildViewController:newViewController];
[self.view addSubview:newViewController.view];
newViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
// TODO: create initial constraints for newViewController.view here
[newViewController.view layoutIfNeeded];
// TODO: update constraint constants here
[UIView animateWithDuration:0.25
animations:^{
[newViewController.view layoutIfNeeded];
}
completion:^(BOOL finished) {
[oldViewController.view removeFromSuperview];
[oldViewController removeFromParentViewController];
[newViewController didMoveToParentViewController:self];
}];
}
Warnings
This is not equivalent to how the storyboard embeds a container view controller. For example, if you compare the translatesAutoresizingMaskIntoConstraints value of the embedded view via a storyboard vs. the method above, it will report YES for the storyboard, and NO (obviously, since we explicitly set it to NO) for the method I recommend above.
This can lead to inconsistencies in your app, since certain parts of the system seem to depend on UIViewController containment to be used with translatesAutoresizingMaskIntoConstraints set to NO. For example, on an iPad Air (8.4), you may get strange behavior when rotating from portrait to landscape.
The simple solution seems to be to keep translatesAutoresizingMaskIntoConstraints set to NO, then set newViewController.view.frame = newViewController.view.superview.bounds. However, unless you are very careful with when this method is called, it most likely will give you an incorrect visual layout. (Note: The way that the storyboard ensures the view sizes properly is by setting the embedded view's autoresize property to W+H. Printing out the frame right after adding the subview will also reveal a difference between the storyboard vs. programatic approach, which suggests that Apple is setting the frame directly on the contained view.)
I hope your question gains some traction because I think it's a good one. I don't have a definitive answer for you, but I can describe my own experiences with situations similar to yours.
Here's the conclusion I have drawn from my experiences: you can't use auto layout directly on the root view of a view controller. As soon as I set translatesAutoresizingMaskIntoConstraints to NO on a root view, I start getting bugs–or worse.
So I use a hybrid solution instead. I set frames and use autoresizing to position and size the root view in a layout that is otherwise configured by auto layout. For example, here's how I load a page view controller as child view controller in viewDidLoad in an app that uses auto layout:
self.pageViewController = ...
...
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
// could not get constraints to work here (using autoresizing mask)
self.pageViewController.view.frame = self.view.bounds;
[self.pageViewController didMoveToParentViewController:self];
This is the way Apple loads a child view controller in the Xcode "Page-Based Application" template–and this is performed in an auto layout enabled project.
So if I were you, I would try setting frames to animate the view controller transition and see what happens. Let me know how it works.
I can't find this anywhere. So, if you possess the info about it, please give me a link.
I have one view controller, I made a menu for a simple game. There are some buttons on it.
I have another view controller and there some buttons too.
The question is:
"How I can do an animation of this buttons (hiding off the screen) after I choose one button that triggers a custom segue (without any animation) to another View Controller, which will run it's button animation(coming to the screen from a border of the screen)?"
I made this like this:
1) Theory: I make a IBAction for a menu button, then in this IBAction I call an animation method, which call a performSegueMethod:. After this in new VC in viewWillAppear method call a animation method (that almost equal method from source VC). All this works, but this don't look smooth. The problem with this animation occurs when destination VC replace source VC. There is some split second, when all looks static, and only after this animation starts.
I don't know how to remove this destination VC lag. May be I must load a destination view before a segue? I tried to do this, but may be a made something wrong, or it's just don't help me.
2) Practice:
firstViewController.m:
- (IBAction)newGameSegueButton {
[self menuSlideInDirection:#"CenterToLeft" performingSegueWithIdentifier:#"mode"];
}
-(void)menuSlideInDirection:(NSString *)direction performingSegueWithIdentifier:(NSString *)segueIdentifier
{
[UIView animateWithDuration:0.4 animations:^{
CGPoint newGameButtonCenter;
newGameButtonCenter.x = directionIndex * 160;
newGameButtonCenter.y = self.gameButtonSlide.center.y;
self.gameButtonSlide.center = newGameButtonCenter;
[UIView animateWithDuration:0.3 delay:0.1 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
//some animation too
} completion:nil];
[UIView animateWithDuration:0.2 delay:0.2 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
//animation
} completion:nil];
[UIView animateWithDuration:0.1 delay:0.3 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
//some animation too
} completion:^(BOOL finished){
if(segueIdentifier){
[self performSegueWithIdentifier:segueIdentifier sender:self];
}
}];
}];
}
Okay, then custom segue code is pretty simple:
-(void)perform
{
UIViewController *src = self.sourceViewController;
UIViewController *dst = self.destinationViewController;
[src.navigationController pushViewController:dst animated:NO];
}
And my secondViewController.m:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self menuSlideInDirection:#"RightToCenter" performingSegueWithIdentifier:nil];
}
menuSlideInDirection:#"RightToCenter" performingSegueWithIdentifier:nil in secondViewController identical to method with same name in firstView.
I'm looking for smooth animation of particular objects of destination view controller right after a segue.
May be a doing all wrong and there a another way to do this? (I only think of adding all view and all controls of destination VC to source VC and remove "destination VC" at all).
Hope, somebody can help me with this.
Try doing all first view controller's animations in perform method.
As for the second view controller's animations, I don't think there is any other 'good' way than doing it in viewWillAppear (although I would prefer viewDidAppear) since the outlets of the destination view controller are not set while performing the segue(they will be nil). In other words, you do not have a way to access your buttons, let alone animate them.
A hackish way would be to call [segue.destinationViewController view] before perform so that the destination view controller's view hierarchy is loaded and the outlets are set. Then perhaps, you may animate buttons in the destination view controller in perform before pushing it onto navigation stack.
For my question, I choose the way of putting two views under the same VC. Animation is smooth and it's look much better than using perform / viewWillAppear method.
I am struggling with understanding why the first method below works for hiding and removing a subview of a view. In this first method I pass the pointer by reference. In the second method, which is less general, I have a delegate method designed for removing a specific view. I would like to use the first method, because I have several views that I would like to apply this too. I should mention that the first method works without fail as long as it is called within the implementing class. It fails when I call it from the view controller that I wish to dismiss. I get an EXC_BAD_ACCESS on the removeFromSuperview line when it fails in the first method.
-(void)closeView:(UIViewController **)viewController
{
[UIView transitionWithView:self.view
duration:UINavigationControllerHideShowBarDuration
options:UIViewAnimationOptionCurveLinear
animations:^
{
[[*viewController view] setAlpha:0.0];
}
completion:^(BOOL finished)
{
[[*viewController view] removeFromSuperview];
[*viewController release], *viewController = nil;
}];
}
-(void)closeButtonClicked
{
[delegate closeView:&self];
}
//
// This method works without fail:
//
-(void)closeView
{
[UIView transitionWithView:self.view
duration:UINavigationControllerHideShowBarDuration
options:UIViewAnimationOptionCurveLinear
animations:^
{
// In this context viewController is defined in the class interface
[[viewController view] setAlpha:0.0];
}
completion:^(BOOL finished)
{
[[viewController view] removeFromSuperview];
[viewController release], viewController = nil;
}];
}
-(void)closeButtonClicked
{
[delegate closeView];
}
First of all, it is not according to the style guides, and not a good idea in general, to do a release of the viewController within a method like this. It will get you into trouble quickly. If the caller of this method is responsible for the viewController (it has done the retain), then it should release it as well. This is likely the cause of the first method not working from within the viewcontroller itself.
In the second method you do not pass in the viewController as parameter, which means it needs to be defined in the context.
If you don't release the viewController in this method, then you don't need to set its variable to nil either, and you can simply pass it as normal parameter:
-(void)closeView:(UIViewController *)viewController
{
[UIView transitionWithView:self.view
duration:UINavigationControllerHideShowBarDuration
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^
{
[[viewController view] removeFromSuperview];
}
completion:nil];
}
you would then do this at the call-site:
[self closeView:childViewController];
[childViewController release]; childViewController = nil;
It safe to release the child in this way before the animation is done, because the animations block implicitly retains all objects referenced from the block, including the viewController parameter. Therefore, the child's dealloc is not called until the animations block releases it.
This does not work in your first code example, because you pass a pointer to a variable. That is, the animations block does not know it needs to retain the child.
BTW, I am not sure why you want to set the alpha, in the example above I show that you can also remove the view already in the animations block. See more about that in the UIView Class Reference.
**viewcontroller and &self is not the way to go. In Objective-C, you do [self.view removeFromSuperview] in the subview itself, in the parent viewcontroller you do release or with ARC just replace the subview with another view.