【问题标题】:Warning: Attempt to present * whose view is not in the window hierarchy警告:尝试呈现 * 其视图不在窗口层次结构中
【发布时间】:2014-06-27 17:47:39
【问题描述】:

首先我要感谢大家! :)

所以,我有一个带有表格视图的主视图控制器,以及来自另一个类的自定义单元格。我已经对单元格进行了自定义选择(您必须滑动视图的单元格)。在那个动作中,我在主视图控制器中调用方法来发送短信。但是我收到了这个警告,并且 SMS 控制器没有出现。我知道,这个错误信息的意思是,它不能打开 SMS 控制器,因为主控制器没有加载?我从这里尝试了一些代码,但对我没有任何作用。我的课程目前看起来像这样:

Main controller.m

.
.
.

-(void)viewWillAppear:(BOOL)animated
{
    [self.citiesButton setTitle:rowValue forState:UIControlStateNormal];

    UITableView *tableView = (id)[self.view viewWithTag:1];
{
    tableView.rowHeight = 100;
    UINib *nib  = [UINib nibWithNibName:@"TableViewCell" bundle:nil];
    [tableView registerNib:nib forCellReuseIdentifier:CellTableIdentifier];

    UIEdgeInsets contentInset = tableView.contentInset;
    contentInset.top = 20;
    [tableView setContentInset:contentInset];

    NSLog(@"rowValue is %@", rowValue);
    self.city = [_dict objectForKey:rowValue];
}

    NSLog(@"View will appear");
    [tableView reloadData];
}

-(void)sendSMS
{
    MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
    if([MFMessageComposeViewController canSendText])

    {
        controller.body = @"Testy Test";
        controller.recipients = [NSArray arrayWithObjects:@"774252704", nil];
        controller.messageComposeDelegate = self;

        [self dismissViewControllerAnimated:YES completion:^{
        [self presentViewController:controller animated:YES completion:nil];
    }];

}
}

所以我试图先关闭主控制器,然后显示 smsController,但仍然没有运气。我认为,问题在于我正在从 TableViewCell 类中调用该方法,但是仍然会在加载视图后创建表,所以我真的迷路了。

非常感谢您的宝贵时间!

=====编辑=====

这是自定义单元格类,我从中调用 sendSMS 方法

tableViewCell.m

#import "TableViewCell.h"
#import "TableViewController.h"

static NSString *CellTableIdentifier = @"TableViewCell";

@implementation TableViewCell

@synthesize timeLabel = _timeLabel;
@synthesize priceLabel = _priceLabel;
@synthesize infoLabel = _infoLabel;


- (void)awakeFromNib
{
    // Initialization code
}


-(void)layoutSubviews
{
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizer:)];

    [self addGestureRecognizer:panGesture];
}


-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    self = [super initWithStyle:style reuseIdentifier:CellTableIdentifier];



    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

-(void)panGestureRecognizer:(UIPanGestureRecognizer *)sender{
    CGPoint translation = [sender translationInView:self];

    TableViewController *mainController = [[TableViewController alloc] init];

    //NSLog(@"Panned with translation point: %@", NSStringFromCGPoint(translation));

    sender.view.center = CGPointMake(sender.view.center.x + translation.x,
                                 sender.view.center.y);


    CGPoint breakingPoint = CGPointMake(320,sender.view.center.y);
    CGPoint startPoint = CGPointMake(150, sender.view.center.y);
    CGPoint endPoint = CGPointMake(500, sender.view.center.y);

    if (sender.view.center.x <= startPoint.x) {
        sender.view.center = startPoint;
    }

    if (sender.state == UIGestureRecognizerStateEnded) {
        if (sender.view.center.x >= breakingPoint.x) {

            [UIView animateWithDuration:0.2
                              delay:0.0
                            options: UIViewAnimationOptionCurveEaseOut
                         animations:^{
                             sender.view.center = endPoint;
                         }
                         completion:^(BOOL finished){
                             NSLog(@"Bought!");
                             [mainController sendSMS];
                         }];

    } else {
        //recognizer.view.center = startPoint;

        [UIView animateWithDuration:0.2
                              delay:0.0
                            options: UIViewAnimationOptionCurveEaseOut
                         animations:^{
                             sender.view.center = startPoint;
                         }
                         completion:^(BOOL finished){
                             NSLog(@"Returned!");
                         }];
    }
}
    [sender setTranslation: CGPointZero inView: self];
}

【问题讨论】:

  • 检查控制器是否在完成块中为零。
  • 试过了,没有运气...我真的卡在这个... 可以是 [tableView reloadData] 在 ViewWillAppear 的错误吗?
  • 你能显示你调用 [self sendSMS] 的代码吗?
  • 好的,我添加了你需要的代码;)

标签: ios iphone objective-c cocoa-touch


【解决方案1】:
- (void)presentViewController:(UIViewController *)viewController animated:(BOOL)animated onComplete:(void (^)(void))callback
{
    AppDelegate *APP_DELEGATE = [UIApplication sharedApplication].delegate;

    UIViewController *presentedModalVC = [APP_DELEGATE.window.rootViewController presentedViewController];

    if (presentedModalVC) {
        while (presentedModalVC.presentedViewController) {
            presentedModalVC = presentedModalVC.presentedViewController;
        }
        [presentedModalVC presentViewController:viewController animated:animated completion:callback];
    } else {
        [APP_DELEGATE.window.rootViewController presentViewController:viewController animated:animated completion:callback];
    }
}

-(void)sendSMS
{
    MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
    if([MFMessageComposeViewController canSendText])

    {
        controller.body = @"Testy Test";
        controller.recipients = [NSArray arrayWithObjects:@"774252704", nil];
        controller.messageComposeDelegate = self;

        [self presentViewController:controller animated:YES onComplete:nil];
    }              
}

你必须在当前展示的 vc 上展示你的 vc,如果存在的话,即如果你有这个展示的 vc 的层次结构

VC1--- VC2 - 由 VC1 提出----- VC3 - 由 VS2 呈现---- ... VCx - 由 x-1 提供

那么您必须在 VCx 上展示您的新 vc,即在当前展示/可见的最后一个 vc 上。

【讨论】:

  • 你能在我的代码中实现这个吗?我还是想不通……非常感谢!
  • 好的,尝试了这个解决方案,但仍然没有运气......仍然是同样的错误!
  • 啊,好的,现在可以了,忘记编辑sendSMS方法了...非常感谢您的帮助!!!
【解决方案2】:

我根据描述的猜测(如果我正确理解您的代码)是您关闭 mainViewController,然后在它消失后您将它呈现视图控制器。由于已被驳回,因此不允许展示任何内容。

就像当女童子军来你家送你的饼干时,你告诉她们“回家不要回来,回家后把我的饼干放在我的前门。”

尝试将关闭 mainViewController 然后将新控制器呈现到最初呈现 mainViewController 的视图控制器中的代码移动。

编辑:

我在您的 UITableviewCell 类中发现了另一个错误。问题在于这一行,位于您的 panGestureRecognizer 函数中。

TableViewController *mainController = [[TableViewController alloc] init];

您创建一个 mainController 实例,然后在几行之后调用

[mainController sendSMS];

它试图呈现一个视图控制器,但是 mainController 的实例从未被推送到视图堆栈上,因此出现了错误。

您需要做的是在 tableviewController 实例上调用 sendSMS,该实例是保存 tableview 的实例,因此也是 tableViewCell。这是另一篇关于如何做到这一点的帖子Reference from UITableViewCell to UITableView to UINavigationController

【讨论】:

  • 不错的答案! :) 无论如何,如果我理解正确,删除 sendSMS 方法中的 dissmiss 部分并留在那里就足够了吗? [self presentViewController:controller animated:YES completion:nil] 因为这样是同一个问题
  • 是的,应该可以。可以同时以模态方式呈现多个视图控制器。每次对dismissViewController 的调用都会像堆栈一样关闭顶部的调用。
  • 更新了答案。您试图让您的 tableviewCell 与拥有它的 tableviewController 进行通信,但您没有正确执行。相反,您创建 UITableviewController 的新实例
  • 另一篇关于如何从单元格stackoverflow.com/questions/1110482/…获取对 UITableViewController 的引用的参考文章
  • 你能在我放在这里的代码中显示它吗?我还是想不通……非常感谢!
猜你喜欢
  • 2020-08-07
  • 1970-01-01
  • 2013-02-23
  • 2017-07-18
  • 2014-11-19
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 2015-11-16
相关资源
最近更新 更多