[iOS开发]present和push

Posted Billy Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[iOS开发]present和push相关的知识,希望对你有一定的参考价值。

present和push:

  • push与present都可以推出新的界面。
  • present与dismiss对应,push和pop对应。
  • present只能逐级返回。
  • push在内存中是以压栈的方式,跳转到摸个控制器,跳转后控制器都存放在Navigation中的ViewControllers数组中。可以返回上一级,也可以返回到根ViewController,其他ViewController。

假设从A控制器通过present的方式跳转到了B控制器,那么
A.presentedViewController 就是B控制器,
B.presentingViewController 就是A控制器。
下面我们会使用程序观察体会。

第一个ViewController中:

- (void)present {
    SecondViewController *secondViewController = [[SecondViewController alloc] init];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:secondViewController];
    nav.modalPresentationStyle = UIModalPresentationFullScreen;
    [self presentViewController:nav animated:YES completion:nil];
    NSLog(@"%p\\n%p", self, self.presentedViewController);
}

第二个ViewController中:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"%p\\n%p", self.navigationController, self.presentingViewController);
    ...
    ...
}

运行结果:
点击并present出第二个视图控制器后输出:

0x12dd07ba0
0x13280a400
0x13280a400
0x12dd07ba0

可以看到A的presentedViewController和B一样,B的presentingViewController和A一样。
上面说过,present对应dismiss,第二个ViewController中的返回事件:

- (void)pressBack {
    [self dismissViewControllerAnimated:YES completion:nil];
}

示例程序的FirstViewController通过present的方式显示以SecondViewController为根视图的navigationController。再之后,Second、Third、Fourth之间的切换都是push和pop。
在Second及以后的视图中试图使用dismissViewController方法,都会回到FirstViewController,比如,第三个页面的backToFirstButton的点击事件为:

- (void)pressToFirst {
    [self dismissViewControllerAnimated:YES completion:nil];
}

这样,点击了按钮后会直接返回第一页面。
前面提到,popViewController方法可以返回上一页,如果要返回得层数更多,可以使用传值方法,将信息传回上一页,再pop一次,示例:
第四页面:

//.h
@protocol FourthBackToSecondDelegate <NSObject>

- (void)backToSecond;

@end

@interface FourthViewController : UIViewController

@property (nonatomic, assign) id<FourthBackToSecondDelegate> delegate;

@end
//.m中返回第二界面的事件
- (void)pressToSecond {
    [self.navigationController popViewControllerAnimated:NO];
    [self.delegate backToSecond];
}

第三个界面:

//.m实现代理函数
- (void)backToSecond {
    [self.navigationController popViewControllerAnimated:YES];
}

这样以来,就可以返回两级页面了,但是十分麻烦,不美观,前面还说过,跳转后控制器都存放在Navigation中的ViewControllers数组中,那么我们是否可以根据这个数组来实现一些操作呢?先打印一下数组看看内容:

//ForthViewController.m中
NSLog(@"%@", self.navigationController.viewControllers);

结果:

(
    "<SecondViewController: 0x15b704710>",
    "<ThirdViewController: 0x159d11d80>",
    "<FourthViewController: 0x15d805870>"
)

可以看到,数组里面果然存放着三个ViewController。这样一来,就可以使用popToRootViewControllerAnimated:或者popToViewController: animated:函数来控制pop到的页面了:

- (void)pressToSecond {
//    [self.navigationController popViewControllerAnimated:NO];
//    [self.delegate backToSecond];
//    [self.navigationController popToRootViewControllerAnimated:YES];
    [self.navigationController popToViewController:self.navigationController.viewControllers[0] animated:YES];
}

这三种结果一样,返回SecondViewController,但使用下面两个自带的函数的动画过渡效果更好,而且代码简单。
下面附上四个Controller.m的代码:

//  ViewController.m
//  PresentAndPush

#import "ViewController.h"
#import "SecondViewController.h"
#import "View.h"

@interface ViewController ()

@property (nonatomic, strong) View *firstView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _firstView = [[View alloc] initWithFrame:self.view.frame];
    [_firstView.pushButton addTarget:self action:@selector(present) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_firstView];
    
}

- (void)present {
    SecondViewController *secondViewController = [[SecondViewController alloc] init];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:secondViewController];
    nav.modalPresentationStyle = UIModalPresentationFullScreen;
    [self presentViewController:nav animated:YES completion:nil];
    NSLog(@"%p\\n%p", self, self.presentedViewController);
}

@end
//  SecondViewController.m
//  PresentAndPush

#import "SecondViewController.h"
#import "SecondView.h"
#import "ThirdViewController.h"

@interface SecondViewController ()

@property (nonatomic, strong) SecondView *secondView;

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"%p\\n%p", self.navigationController, self.presentingViewController);
    _secondView = [[SecondView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:_secondView];
    
    [_secondView.backButton addTarget:self action:@selector(pressBack) forControlEvents:UIControlEventTouchUpInside];
    [_secondView.pushButton addTarget:self action:@selector(pressPush) forControlEvents:UIControlEventTouchUpInside];
}

- (void)pressBack {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)pressPush {
    ThirdViewController *thirdViewController = [[ThirdViewController alloc] init];
    [self.navigationController pushViewController:thirdViewController animated:YES];
}

@end
//  ThirdViewController.m
//  PresentAndPush

#import "ThirdViewController.h"
#import "ThirdView.h"
#import "FourthViewController.h"

@interface ThirdViewController ()<FourthBackToSecondDelegate>

@property (nonatomic, strong) ThirdView *thirdView;

@end

@implementation ThirdViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _thirdView = [[ThirdView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:_thirdView];
    
    [_thirdView.pushButton addTarget:self action:@selector(pressPush) forControlEvents:UIControlEventTouchUpInside];
    [_thirdView.backButton addTarget:self action:@selector(pressBack) forControlEvents:UIControlEventTouchUpInside];
    [_thirdView.backToFirstButton addTarget:self action:@selector(pressToFirst) forControlEvents:UIControlEventTouchUpInside];
}

- (void)pressPush {
    FourthViewController *fourthViewController = [[FourthViewController alloc] init];
    fourthViewController.delegate = self;
    [self.navigationController pushViewController:fourthViewController animated:YES];
}

- (void)pressBack {
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)pressToFirst {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)backToSecond {
    [self.navigationController popViewControllerAnimated:YES];
}

@end
//  FourthViewController.m
//  PresentAndPush

#import "FourthViewController.h"
#import "FourthView.h"

@interface FourthViewController ()

@property (nonatomic, strong) FourthView *fourthView;

@end

@implementation FourthViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _fourthView = [[FourthView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:_fourthView];
    
    [_fourthView.backButton addTarget:self action:@selector(pressBack) forControlEvents:UIControlEventTouchUpInside];
    [_fourthView.backToSecondButton addTarget:self action:@selector(pressToSecond) forControlEvents:UIControlEventTouchUpInside];
    NSLog(@"%@", self.navigationController.viewControllers);
}

- (void)pressBack {
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)pressToSecond {
//    [self.navigationController popViewControllerAnimated:NO];
//    [self.delegate backToSecond];
//    [self.navigationController popToRootViewControllerAnimated:YES];
    [self.navigationController popToViewController:self.navigationController.viewControllers[0] animated:YES];
}
@end

完整代码的Demo地址:https://github.com/BillyMiracle/PushAndPresent.git

以上是关于[iOS开发]present和push的主要内容,如果未能解决你的问题,请参考以下文章

iOS 判断是push还是present

iOS Storyboard Presenting Segues "relationship, embed, push, modal, custom" 类型

ios swift 判断uiviewcontroller时push present 进来的 还是pop进来的

push和present 两种方式。viewWillDisAppear,viewDidDisAppear的顺序

push和present 两种方式。viewWillDisAppear,viewDidDisAppear的顺序

A push B present C push D present E怎么返回A