深入理解present以及dismiss

文章目录

    • 前言
    • GitHubDemo
    • presentingViewController和presentedViewController
      • 文档描述
      • Xcode打印实验
      • 分析
    • 多次弹窗
      • 描述
      • Xcode实验
    • dismiss
      • 文档描述
      • 举个栗子
      • 总结
    • 参考文章

前言

  • present以及dismiss显然是iOS开发最先学到的东西了
  • 项目中出现了要dismiss回上上个viewController,在查找方法时,发现调用present方法的对象可以不是self
  • 显然我对于这两兄弟的理解不是很OK

GitHubDemo

  • present-dismiss-learning
  • 其中包括三个ViewController以及研究中做的一些打印工作

presentingViewController和presentedViewController

文档描述

// The view controller that was presented by this view controller or its nearest ancestor.
//此视图控制器或其最近祖先显示的视图控制器。
@property(nullable, nonatomic,readonly) UIViewController *presentedViewController  NS_AVAILABLE_IOS(5_0);

// The view controller that presented this view controller (or its farthest ancestor.)
//显示此视图控制器(或其最远祖先)的视图控制器。
@property(nullable, nonatomic,readonly) UIViewController *presentingViewController NS_AVAILABLE_IOS(5_0);
  • 放了两段百度上的机翻,几乎没什么用,我们还是来看Xcode上的打印结果如何吧

Xcode打印实验

- (void)touchPresent {
    SecondViewController *secondViewController = [[SecondViewController alloc] init];
    NSLog(@"self--%p--", self);
    NSLog(@"next--%p--", secondViewController);
    NSLog(@"BeforeA:self.presentedViewController--%p--", self.presentedViewController);
    NSLog(@"BeforeA:self.presentingViewController--%p--", self.presentingViewController);
    [self presentViewController:secondViewController animated:YES completion:nil];
    NSLog(@"LaterA:self.presentedViewController--%p--", self.presentedViewController);
    NSLog(@"LaterA:self.presentingViewController--%p--", self.presentingViewController);
}
  • 这是一个在firstViewController中一个button的点击事件,我们在执行present前后分别打印self(即firstViewController的这两个属性)
  • 我们做两次打印试验,第一次是在First弹Second,第二次是在Second弹Third
firstViewController--0x7fe8a2c0cc50--
secondViewController--0x7fe8a2c0cfb0--
thirdViewController--0x7fe8a2f0eb60--
  
 
BeforeA:self.presentedViewController--0x0--
BeforeA:self.presentingViewController--0x0--
LaterA:self.presentedViewController--0x7fe8a2c0cfb0--
LaterA:self.presentingViewController--0x0--
  

BeforeB:self.presentedViewController--0x0--
BeforeB:self.presentingViewController--0x7fe8a2c0cc50--
LaterB:self.presentedViewController--0x7fe8a2f0eb60--
LaterB:self.presentingViewController--0x7fe8a2c0cc50--

分析

  • presentingViewController属性返回父节点,presentedViewController属性返回子节点,如果没有父节点或子节点,返回nil。
  • 不太理解怎么出现文档中的 or its nearest ancestor以及its farthest ancestor,希望有人知道能告诉我

多次弹窗

描述

  • 在这个例子中,我们用First弹Second,之后用Second弹Third,假如我们尝试用First弹Third回发生什么呢

Xcode实验

  • 我们使用属性传值,将first传给second,在弹third的时候由它来执行该方法
Warning: Attempt to present  on  whose view is not in the window hierarchy!
  • Xcode也是毫不含糊的直接给你来发报错,同时,界面也不会有任何改变
  • 因此能执行present的必须得是self(或者说是最顶层的控制器),此外,不管是你新建一个还是想用之前的viewController去弹都是8⃣️行的

dismiss

文档描述

Discussion
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.

If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.

If you want to retain a reference to the view controller's presented view controller, get the value in the presentedViewController property before calling this method.

The completion handler is called after the viewDidDisappear: method is called on the presented view controller.

呈现视图控制器负责解除其呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,uikit会要求呈现视图控制器处理解除。

如果您连续显示多个视图控制器,从而构建一个显示的视图控制器堆栈,则在堆栈中较低的视图控制器上调用此方法会解除其直接子视图控制器和堆栈中该子级以上的所有视图控制器。当发生这种情况时,只有最上面的视图以动画的方式被取消;任何中间视图控制器都只是从堆栈中删除。最上面的视图将使用其模态转换样式来消除,这可能与堆栈中较低的其他视图控制器使用的样式不同。

如果要保留对视图控制器的PresentedView控制器的引用,请在调用此方法之前获取PresentedView控制器属性中的值。

完成处理程序在viewdid消失后调用:方法在显示的视图控制器上调用。

举个栗子

  • 还是A,B,C三个ViewController,我们从A到B到C
  • 第一种情况:[C dismiss] 回到B
  • 第二种情况:[B dismiss] 回到B 直接子视图控制器C和堆栈中该子级以上的所有视图控制器都是C
  • 第三种情况:[A dismiss] 回到A 直接子视图控制器C和堆栈中该子级以上的所有视图控制器B C

总结

  • 直接子视图控制器就是本身,该子级以上的所有视图控制器是指调用者以上的所有视图控制器

  • 所以本质上还是一层层dismiss,只是只有剥除本身的是有动画效果的,因此我们看不到好想一层层剥下去的动画,好想是直接dismiss了一次就到位了,可以说是非常有迷惑性了

参考文章

  • iOS 聊聊present和dismiss

你可能感兴趣的:(Objective-C)