昨天写豆瓣发广播Demo的时候,为了写Demo的简单,就使用了Storyboard,结果执行视图跳转时遇到了这个问题:

Warning: Attempt to present <UINavigationController: 0x8d514e0> on <OAuthViewController: 0xa044a60> whose view is not in the window hierarchy!

其功能是OAuthViewController用于用户授权,在获取用户的授权后将拿到的access_token通过NSUserDefaults保存起来。那么在下一次打开程序时,首先判断access_token是否已经存在,如果已经存在就直接跳转到UINavigationController。代码如下:

- (void)viewDidLoad {
[super viewDidLoad]; spinner_view.hidesWhenStopped = YES;
[webView setDelegate:self];
[webView setScalesPageToFit:YES]; // 如果已经保存了授权用户的access_token,那么直接跳转到UINavigationController
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
access_token = [userDefaults objectForKey:@"access_token"];
if (access_token) {
[self performSegueWithIdentifier:@"gotoSay" sender:nil];
return;
} NSString *paramClientID = [NSString stringWithFormat:@"client_id=%@", API_KEY];
NSString *paramRedirect_uri = [NSString stringWithFormat:@"redirect_uri=%@", REDIRECT_URI];
NSString *paramResponse_type = @"response_type=code";
NSString *paramScope = @"shuo_basic_r,shuo_basic_w,douban_basic_common"; // 在其它API调用时可能要扩展该作用域参数
NSString *getAuthCode = [NSString stringWithFormat:@"%@?%@&%@&%@&%@", GET_AUTHORIZATION_CODE_URL, paramClientID, paramRedirect_uri, paramResponse_type, paramScope]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:getAuthCode]];
[spinner_view startAnimating];
[webView loadRequest:request];
}

问题出现了,无法完成视图的跳转,但是用户的access_token已经在preferences的plist文件中成功保存了。控制台输出的错误信息如上所示。

查了一下资料,发现了问题所在(StackOverflow上面的高手真的很多啊),先给出两个对我很有帮助的网址:

[ios开发异常]whose view is not in the window hierarchy!

loadView、viewDidLoad、viewWillAppear、viewDidAppear等详解

解决方法:

将验证access_token是否已经存在的代码转移到viewDidAppear方法中:

- (void)viewDidAppear:(BOOL)animated {
// 如果已经保存了授权用户的access_token,那么直接跳转到UINavigationController
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
access_token = [userDefaults objectForKey:@"access_token"];
if (access_token) {
[self performSegueWithIdentifier:@"gotoSay" sender:nil];
return;
}
}

分析:

相信进行单步调试的程序员都知道,只有就viewDidLoad方法完全执行完毕,才会真正在window中加载对应的界面。在修改前的程序中就有问题出现了,注意该动作发生在A的viewDidLoad方法中:

[self performSegueWithIdentifier:@"gotoSay" sender:nil];

作用是从A跳转到B中。

那么在segue调用后,程序将调用B的viewDidLoad方法,在B的viewDidLoad方法执行完后,又回到了A的viewDidLoad的方法中执行剩下的语句。那么在window加载视图时其层次结构便发生了混乱,于是报错(当然如果从A跳转到B后面还有语句的话,最后加载的还是A的view)。

viewDidAppear方法和viewDidLoad方法的区别在于:viewDidLoad方法调用时视图还没完全过渡到window中,viewDidAppear方法调用时,视图已经完全过渡到window中了。

所以在viewDidAppear方法中调用performSegue方法实现视图跳转就不会出现以上的问题了,因为程序将有序地先执行A的viewDidLoad方法,在该方法完结后,再在viewDidAppear方法中执行segue跳转并执行B的viewDidLoad方法,这样就不会发生混乱了。

当我想从一个VC跳转到另一个VC的时候,一般会用

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion;当然也可以用导航push。

可是昨天就遇到了题目中的warning,在stackoverflow找到了答案:点击打开链接

大意就是页面跳转必须在viewDidLoad和viewDidAppear之后才能进行。解决的办法就是确保页面跳转要在view load完毕之后进行。大神说可以通过设置延时来实现,通过实验我觉得这个不好控制,到底需要延时多少呢》

后来换了一个方案,在viewDidLoad里用

[selfperformSelectorOnMainThread:@selector(login)withObject:nilwaitUntilDone:NO];

把页面跳转的代码写进函数里,然后将 waitUntilDone 设为NO,就是viewDidLoad直接返回不用等login执行。这样就可以确保login里的页面跳转是在viewDidLoad之后执行。

另外,我还遇到下面这个情况:A页面跳转到B,在B里又封装了一个页面跳转(至C)。

也就是在前面的login函数里,从A跳转至B时会传入token、secret等用来获取用户授权的数据,然后在B里再调各大公司封装好的授权页面(如百度网盘、新浪微博)。

一开始我的login实现如下:

-(void)login

{

loginViewController *loginVC=[[loginViewControlleralloc] init];

loginVC.delegate=self;

[self  presentViewController:loginVC animated:NOcompletion:nil];

[loginVC   auth:BAIDU_API_KEY   secret:nil  disk:BAIDU];//这个函数里有跳转至授权页面

}

这同样会出现上面的问题,解决的办法就是把最后一行的函数放在completion的block里。

-(void)login

{

loginViewController *loginVC=[[loginViewController alloc] init];

loginVC.delegate=self;

[self  presentViewController:loginVC animated:NO completion:^{[loginVC auth:BAIDU_API_KEY secret:nil disk:BAIDU];}];

}

因为:

The completion handler, if provided, will be invoked after the presented  controllers viewDidAppear: callback is invoked.

Warning: Attempt to present A on B whose view is not in the window hierarchy!的更多相关文章

  1. Warning: Attempt to present on whose view is not in the window hierarchy!

    当我想从一个VC跳转到另一个VC的时候,一般会用 - (void)presentViewController:(UIViewController *)viewControllerToPresent a ...

  2. Warning: Attempt to present * on * which is already presenting *

    Warning: Attempt to present (要被presented的控制器)  on (哪个控制器来presenting) which is already presenting (已经 ...

  3. 错误:Warning: Attempt to present <UIAlertController: 0x7fd192806e20> on <ViewController: 0x7fd1928048d0> whose view is not in the window hierarchy!

    系统:mac OS  10.12 (16A323) Xcod:8.3.3 错误:Warning: Attempt to present <UIAlertController: 0x7fd1928 ...

  4. Attempt to present <TestViewController2: 0x7fd7f8d10f30> on <ViewController: 0x7fd7f8c054c0> whose view is not in the window hierarchy!

    当 storyboard里面的 按钮 即连接了 类文件里面的点击方法  又  连接了   storyboard里 另一个  控制器的  modal 就会出现类似Attempt to present & ...

  5. swift一次 Attempt to present on whose view is not in the window hierarchy的解决方法

    做的是二维码扫描,扫描后识别为URL的话就跳转到webview 加载网页,用的是代理传值的方式.扫描到了 值传递到主页 扫描窗体退出,检测值是否是http://开头 是网页就跳转. 问题出在传值到主界 ...

  6. Warning: Attempt to present on whose view is not in模态跳转问题

    错误分析:            controller A present controller B ,前提是A的view要存在,如果不存在,就会报这个错.   解决方法:             将 ...

  7. iOS8 iPad Warning: Attempt to present <UIImagePickerController:xxxx > on xxxx which is already presenting (null)

    解决方法: /* I think this is because in iOS 8, alert views and action sheets are actually presented view ...

  8. Attempt to present <vc> on <vc> which is already presenting <vc>/(null)

    在给 tableViewCell 添加长按手势弹出一个 popViewController 的时候,遇到的这个变态问题: Warning: Attempt to present <UINavig ...

  9. 跳转时候提示Attempt to present on while a presentation is in progress

    出现这种情况,例如:我在获取相册图片后,直接present到另一个页面,但是上一个页面可能还未dismiss,所以,要在获取相册图片的dismiss方法的complete的block里面写获取图片及跳 ...

随机推荐

  1. SHOW CREATE语句

    show create table tablename 查看某表的建表语句 同理查看存储过程 show create procedure  sp_name

  2. delphi XE7 判断手机返回键

    Using the Android Device's Back Button To make your application handle when users press the Back but ...

  3. javascript中 try catch用法

    javascript中 try catch用法 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2015-08-16我要评论 JS try catch语句一般在什么情况下使用?是必须使 ...

  4. Hibernate hql 多表查询

    String hql="select c from Col c ,UserRole role where c.id=role.columnId and c.id=? and role.use ...

  5. Mysql一些记忆

    mysql修改密码报错是yum 安装mysql5.7 是 出现无法登陆问题以及mysql error You must reset your password using ALTER USER sta ...

  6. Mycat入门及简单规则

    以下都来自网络: 官网: http://www.mycat.io/ 官网配置文件解析: https://github.com/MyCATApache/Mycat-Server/wiki/9.0-%E6 ...

  7. go 第一个项目

    官方下载go: https://golang.org/dl/ 安装完成后:cmd命令下:go go env:查看当前的环境配置:

  8. General error 2006 MySQL server has gone away

    写入配置文件的办法: max_allowed_packet = 16M //但是这种有时候不支持,1024*1024*16这种有的也不支持 max_allowed_packet = 16777216 ...

  9. golang interface接口

    package main import "fmt" type Shaper interface { Area() float32 } type Square struct { si ...

  10. 安卓机在按HOME键时,UNITY触发的APPLICATION_PAUSE事件

    安卓机在按HOME键时,UNITY触发的APPLICATION_PAUSE事件 此时安卓程序会返回,在这一瞬间,程序可以通过SOCKET发送数据包给服务器告知, 经测试在这短暂的时间内,这个数据包能发 ...