gpt4 book ai didi

iphone - 警告: Attempt to present ViewController on ViewController whose view is not in the window hierarchy

转载 作者:技术小花猫 更新时间:2023-10-29 11:12:13 25 4
gpt4 key购买 nike

我已经看过相关的问题,但是没有任何问题可以解决我的问题。

我正在尝试连续使用dismissViewControllerAnimated:animated:completionpresentViewControllerAnimated:animated:completion。使用 Storyboard ,我通过部分 curl 动画模态呈现InfoController。

部分 curl 在InfoController上显示了一个我想启动MFMailComposeViewController的按钮。因为部分 curl 部分隐藏了MFMailComposeViewController,所以我首先要通过取消部分 curl 的动画来关闭InfoController。然后我想要MFMailComposeViewController进行动画处理。

目前,当我尝试此操作时,部分 curl 不会激活,但是MFMailComposeViewController没有显示出来。我也有以下警告:

Warning: Attempt to present MFMailComposeViewController: on InfoController: whose view is not in the window hierarchy!



InfoController.h:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>

@interface InfoController : UIViewController <MFMailComposeViewControllerDelegate>

@property (weak, nonatomic) IBOutlet UIButton *emailMeButton;

-(IBAction)emailMe:(id)sender;

@end

InfoController.m
#import "InfoController.h"

@interface InfoController ()

@end

@implementation InfoController

- (void)viewDidLoad
{
[super viewDidLoad];
}

- (IBAction)emailMe:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
[self sendMeMail];
}];
}

- (void)sendMeMail {
MFMailComposeViewController *mailController = [[MFMailComposeViewController alloc] init];
if([MFMailComposeViewController canSendMail]){
if(mailController)
{
NSLog(@"%@", self); // This returns InfoController
mailController.mailComposeDelegate = self;
[mailController setSubject:@"I have an issue"];
[mailController setMessageBody:@"My issue is ...." isHTML:YES];
[self presentViewController:mailController animated:YES completion:nil];
}
}
}

- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error;
{
if (result == MFMailComposeResultSent) {
NSLog(@"It's sent!");
}
[self dismissViewControllerAnimated:YES completion:nil];
}

另外,如果我在 [self dismissViewControllerAnimated:YES completion:^{}];中注释掉 (IBAction)emailMe,则 MFMailComposeViewController会动画化,但它会部分隐藏在部分 curl 的后面。如何首先消除 curl ,然后在 MFMailComposeViewController中设置动画?

非常感谢!

编辑:如果我注释掉 [self dismissViewControllerAnimated:YES completion:^{}];,则 View 外观如下图所示

enter image description here

最佳答案

这是由于不清楚的父 subview Controller 关系导致的 View Controller 之间的通信问题。如果不使用协议(protocol)和委托(delegate),则无法正常工作。

经验法则是:

  • parent 了解他们的 child ,但是 child 不需要了解他们的 parent 。

  • (听起来很无情,但是如果您考虑一下,这是有道理的)。

    转换为ViewController关系:呈现 View Controller 需要了解其 subview Controller ,但是 subview Controller 必须不了解有关其父(呈现) View Controller 的信息: subview Controller 使用其委托(delegate)将消息发送回其(未知) parent 。

    您知道如果必须在 header 中添加@Class声明来修复已链接的#import编译器警告,那是不对的。交叉引用始终是一件坏事(顺便说一句,这也是为什么委托(delegate)应该始终为(分配)且永不为(强)的原因,因为这将导致交叉引用循环和一组僵尸)

    因此,让我们来看一下项目中的这些关系:

    就像您没有说的那样,我假设调用 Controller 的名称为MainController。因此,我们将拥有:
  • MainController,父级,拥有并呈现InfoController
  • 一个InfoController(部分透露于MainController下面),拥有并呈现:
  • MailComposer,无法显示,因为它将显示在MainController下方。

  • 所以你想拥有这个:
  • MainController,父级,拥有并呈现InfoController和MFMailController
  • 一个InfoController(在MainController下面部分透露)
  • 在InfoController的 View 中为“电子邮件按钮”。单击时,它将通知MainController(它是未知的委托(delegate))它应该关闭InfoController(它自己)并显示MailComposer
  • 一个MailComposer,它将由MainController而非InfoController拥有(呈现和关闭)

    1. InfoController:定义一个@protocol InfoControllerDelegate:

    子 Controller 定义一个协议(protocol),并具有一个未指定类型的委托(delegate),该委托(delegate)符合其协议(protocol)(换句话说:委托(delegate)可以是任何对象,但必须具有此一种方法)
    @protocol InfoControllerDelegate
    - (void)returnAndSendMail;
    @end

    @interface InfoControllerDelegate : UIViewController // …

    @property (assign) id<InfoControllerDelegate> delegate

    // ...

    @end

    2. MainController拥有并创建InfoController和MFMailController

    ...并且MainController同时采用了InfoControllerDelegate和MFMailComposeDelegate协议(protocol),因此它可以再次关闭MFMailComposer(请注意,这不是而且很可能不需要强属性,只需在此处显示即可清楚)
    @interface MainController <InfoControllerDelegate, MFMailComposeViewControllerDelegate>

    @property (strong) InfoController *infoController;
    @property (strong) MFMailComposeViewController *mailComposer;

    3. MainController呈现其InfoViewController并将其自身设置为委托(delegate)
    // however you get the reference to InfoController, just assuming it's there
    infoController.delegate = self;
    [self presentViewController:infoController animated:YES completion:nil];

    “infoController.delegate = self”是关键步骤。这使infoController可以在不知道ObjectType(类)的情况下将消息发送回MainController。无需#import。它所知道的只是它是一个具有-returnAndSendMail方法的对象;这就是我们需要知道的。

    通常,您将使用alloc/init创建viewController,并让它延迟加载xib。
    或者,如果您正在使用 Storyboard 和Segues,则可能要拦截(在MainController中)segue,以便以编程方式设置委托(delegate):
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // hook in the segue to set the delegate of the target
    if([segue.identifier isEqualToString:@"infoControllerSegue"]) {
    InfoController *infoController = (InfoController*)segue.destinationViewController;
    infoController.delegate = self;
    }
    }

    4.在InfoController中,按下电子邮件按钮:

    当按下电子邮件按钮时,将调用委托(delegate)(MainController)。请注意,self.delegate是MainController无关紧要,它具有此方法-returnAndSendMail无关紧要
    - (IBAction)sendEmailButtonPressed:(id)sender {
    // this method dismisses ourself and sends an eMail
    [self.delegate returnAndSendMail];
    }

    ...然后在这里(MainController中的!),您将关闭InfoController(清理是因为这是MainController的责任),并提供MFMailController:
    - (void)returnAndSendMail {
    // dismiss the InfoController (close revealing page)
    [self dismissViewControllerAnimated:YES completion:^{
    // and present MFMailController from MainController
    self.mailComposer.delegate = self;
    [self presentViewController:self.mailComposer animated:YES completion:nil];
    }];
    }

    因此,使用MFMailController进行的操作实际上与使用InfoController进行的操作相同。两者都有其未知的委托(delegate),因此他们可以发回邮件,如果有,您可以将其解雇并继续执行您应做的事情。

    注释
  • -dismissViewControllerAnimated:completion:不应从 subview Controller 中调用。在文档中,它说:“呈现的 View Controller 负责关闭其呈现的 View Controller 。”。这就是为什么我们仍然需要委派。这很有用,因为 parent 的关系和责任很重要!的确。您不能创建某些东西,然后就保留它。好吧,可以,但是不可以。
  • 如果您不使用显示 View Controller 动画,则可以链接这些父对象(采用子协议(protocol))-子对象(为父代定义协议(protocol),为孙子代采用协议(protocol))-孙子(为...
  • 定义协议(protocol))
  • 再次:一个拥有MainController并呈现所有子viewController的设计确实是一个糟糕的设计。因此,提出的解决方案是关于协议(protocol)和通信的,而不是将所有内容都放在一个MainController中
  • 我不认为将块作为一种编码技术可以使我们摆脱定义关系和声明协议(protocol)的需要。
  • 希望对
  • 有帮助

    关于iphone - 警告: Attempt to present ViewController on ViewController whose view is not in the window hierarchy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16384121/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com