简体   繁体   中英

viewDidAppear called on a viewcontroller which is being dismissed in iOS8

Let us assume ParentViewcontroller as P, FirstViewController as V1 and SecondViewController as V2.

I'm presenting V1 from P then V2 from V1. Now I want to go directly to P. For this I'm using

[self.presentingViewController.presentingViewController dismissViewControllerAnimated:NO completion:nil];

This works fine in iOS7. But in iOS8 I'm facing an issue(don't know whether it is issue or not) when doing this. That is V1's viewDidAppear method is being called and also its view glitches on the screen for a fraction of second.

Is this iOS8 feature or bug?. Is there any alternative way to do this?

ViewControllers presenting code.

From P, where P is a pushed viewcontroller,

ViewController1 *v1 = [[ViewController1 alloc] init];      
[self presentViewController:v1 animated:NO completion:nil];

From V1,

ViewController2 *v2 = [[ViewController2 alloc] init];
[self presentViewController:v2 animated:NO completion:nil];

Can you use your V1 embed in NavigationController (NV) ? In this way, you can push your V2. Then you can pop to V1 or dismiss NV to P.

After spending a lot of time in researching ended up by patching the issue.

What I did is, before dismissing the ViewController(V2) I captured a screen-shot of ParentViewcontroller(P) and added it to the application window. Then removed the image from the window after the ViewController(V2)'s dismissal.

CGRect deviceRect = [[UIScreen mainScreen] bounds];

UIGraphicsBeginImageContextWithOptions(deviceRect.size, NO, [UIScreen mainScreen].scale);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(contextRef, -deviceRect.origin.x, -deviceRect.origin.y);
[[self.presentingViewController.presentingViewController.view layer] renderInContext:contextRef];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

UIImageView *windowImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, deviceRect.size.width, deviceRect.size.height)];
[windowImageView setImage:capturedImage];
[[[UIApplication sharedApplication] keyWindow] addSubview:windowImageView];

[self.presentingViewController.presentingViewController dismissViewControllerAnimated:NO completion:^
{
      [windowImageView removeFromSuperview];
}];

The fact that 'viewWill/DidAppear' is invoked when you dismiss V1 is logical as technically V1 is exposed in the modal dismissal of the top viewController (V2), if only for long enough that UIKit then gets tasked to remove the next underlying viewController (eg V1).

My guess would be the V1 visual glitch in iOS8 is not a bug and more to do with how iOS deals with dismissal of a modal-inside-a-modal in iOS8. Since no documentation exists for that situation its actual behavior can legitimately change from iOS to iOS.

I think one way to do what you want to do, keep your backwards compatibility to older iOS's, and use API's with documented behavior, would be using code such as below (perhaps as a category on UIViewController). to animate V1 up, then later simply remove it (#2 below). V2 could probably be animated up inside V1 using the standard iOS 'presentViewController', but you could also use method #1 for it.

One note is that since you are adding V1.view as a subview to P instead of through the UIViewController modal system, you will lose the automated viewWill/DidAppear calls in V1. So you would need to invoke those manually. In this example they are invoked in the 'animate up' category method.

This isn't code I'm actually using, but I've done similar things in the past. So be a little careful and please comment if errors are found....assumes ARC:

Hope this helps.

    //1. animate V1 up (executed from P)
    ViewController  * V1 = [[ViewController1 alloc] init];
    //place V1 view below bottom of P
    V1.view.frame = CGRectMake(0, UI_phone_height, UI_phone_width, UI_phone_height);
    [self.view addSubview: V1.view]; //'self' is P
    [V1 customAnimateUpCategory];

    // >> method #1 in a UIViewController category
    - (void) customAnimateUpCategory {

            //...optional
            [self viewWillAppear];

            [UIView animateWithDuration:0.4
                     animations:^ {
                         //animate V1.view up
                         self.view.frame = CGRectMake(0, 0, UI_phone_width, UI_phone_height);
                     }
                     completion:^ (BOOL finished) {
                         if (finished) {
                             //...optional
                             [self viewDidAppear];
                         }
                     }
            ];
    }


    //2. make V1/V2 disappear without animation (executed from V2)
    //'V1' is weakly held in V2 as an IVAR
    [self.V1 removeViewCategory]

    // >> method #2 in a UIViewController category
    - (void) removeViewCategory {
            [self.view removeFromSuperview];//should remove and release V1/V2 glitch free!!
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM