Avertissement: Essayez de présenter ViewController sur ViewController dont la vue ne se trouve pas dans la hiérarchie des fenêtres
Je l'ai déjà regardé à travers des questions, mais rien n'a résolu mon problème.
Je suis d'essayer d'utiliser dismissViewControllerAnimated:animated:completion
et presentViewControllerAnimated:animated:completion
dans la succession. À l'aide d'un storyboard, je suis modal présentant InfoController par l'intermédiaire d'une partielle curl animation.
Partielle curl révèle un bouton sur InfoController que je veux lancer le MFMailComposeViewController
. Parce que la partielle curl cache partiellement la MFMailComposeViewController
je tiens tout d'abord à rejeter InfoController par l'onu-l'animation de la partielle du roulage. Ensuite, je veux le MFMailComposeViewController
pour animer.
À l'heure actuelle, lorsque j'essaie de cela, l'partielle curl onu-anime, mais le MFMailComposeViewController
n'obtient pas présenté. J'ai aussi un avertissement:
Avertissement: Tentative de présenter MFMailComposeViewController:
InfoController: dont la vue n'est pas dans la fenêtre hiérarchie!
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];
}
Aussi, si j'en commentaire le [self dismissViewControllerAnimated:YES completion:^{}];
dans (IBAction)emailMe
le MFMailComposeViewController
anime, mais c'est partiellement caché derrière l'partielle curl. Comment puis-je d'abord rejeter la boucle et puis d'animer dans le MFMailComposeViewController
?
Merci beaucoup!
Edit: ci-Dessous de l'image de ce que la vue est comme si j'commentaire [self dismissViewControllerAnimated:YES completion:^{}];
source d'informationauteur dianna
Vous devez vous connecter pour publier un commentaire.
C'est un problème de communication entre la vue-des contrôleurs résultant d'un manque d'parent-enfant-vue-contrôleur de la relation... Sans l'aide d'un protocole et de la délégation, cela ne fonctionnera pas correctement.
La règle de base est:
(Sons, sans cœur, mais il est logique, si vous pensez à ce sujet).
Traduit de ViewController relations: la Présentation de la vue des contrôleurs besoin de savoir au sujet de leur enfant à la vue des contrôleurs, mais la vue enfant contrôleurs ne doivent pas connaître au sujet de leur parent (présentation) afficher les contrôleurs de l'enfant: la vue des contrôleurs utilisent leurs délégués pour envoyer des messages de retour de leur (inconnue) des parents.
Vous savez que quelque chose est mauvais si vous avez à ajouter @déclarations de Classe dans vos en-têtes à résoudre enchaîné #import des avertissements du compilateur. Références croisées sont toujours une mauvaise chose (btw, c'est aussi la raison pour laquelle les délégués doivent toujours être (attribuer) et jamais (forte), ce qui permettrait d'une référence croisée à boucle et d'un groupe de Zombies)
Alors, penchons-nous sur ces relations pour votre projet:
Que vous n'avez pas dit, je suppose que l'appel contrôleur est nommé MainController. Nous allons donc nous avons:
Vous voulez donc avoir ceci:
1. InfoController: Définit un @protocole InfoControllerDelegate:
Le contrôleur enfant définit un protocole et dispose d'un délégué de type non spécifié qui est conforme à son protocole (en d'autres termes: le délégué peut être n'importe quel objet, mais il doit avoir cette méthode)
2. MainController possède et crée à la fois InfoController et MFMailController
...et la MainController adopte à la fois la InfoControllerDelegate et la MFMailComposeDelegate protocole, de sorte qu'il peut rejeter la MFMailComposer à nouveau (Remarque, qui n'est pas et ne devrait probablement pas besoin d'être fort propriétés, il suffit de montrer ici à préciser)
3. MainController présente ses InfoViewController et définit lui-même comme le délégué
Le " infoController.delegate = self " est l'étape cruciale. Cela donne à la infoController une possibilité d'envoyer un message à l'MainController sans le savoir ObjectType (Classe). Pas de #import nécessaire. Tous les il sait, c'est que c'est un objet qui a de la méthode returnAndSendMail; et c'est tout ce que nous devons savoir.
En règle générale, vous créez votre viewController avec alloc/init et le laisser charger ses xib paresseusement.
Ou, si vous travaillez avec des story-boards et Enchaîne, vous voulez probablement pour intercepter la séquence (en MainController) afin de définir le délégué du programme:
4. Dans InfoController, le bouton e-mail est pressé:
Lorsque l'eMail est enfoncé, le délégué (MainController) est appelée. Notez qu'il n'est pas pertinent que l'auto.délégué est le MainController, c'est juste que c'est cette méthode -returnAndSendMail
...et ici (dans MainController!), vous allez rejeter la InfoController (nettoyer, car il est de la responsabilité de l'MainController) et de présenter les MFMailController:
donc, ce que vous faites avec le MFMailController est pratiquement le même qu'avec la InfoController. Les deux ont leurs inconnue délégué, afin qu'ils puissent message de retour et s'ils le font, vous pouvez les fermer et procéder avec tout ce que vous devez faire.
Notes
Lorsque vous présentez un viewController, le viewController de vous présenter de doit être dans le point de vue de la hiérarchie. Les deux CR de tenir des pointeurs vers les uns les autres dans leurs propriétés
presentingViewController
etpresentedViewController
de sorte que les deux contrôleurs ont besoin d'être dans la mémoire.En rejetant alors l'exécution de la présentation du code à partir de l'être-rejeté-vue-contrôleur, vous êtes en rupture de cette relation.
Au lieu de cela, vous devriez être en train de faire la présentation de votre
mailController
de la viewController que présentéInfoController
après lainfoController
a été rejeté.La trad façon de le faire est par l'intermédiaire d'un délégué de rappel pour le sous-viewController qui gère ensuite les deux étapes de les rejeter et de les présenter. Mais maintenant, nous utilisons des blocs..
Déplacer votre
sendMeMail
méthode dans le CR que présentéinfoController
Puis -
infoController
- vous pouvez l'appeler dans la réalisation de bloc...(vous devez obtenir un pointeur à
self.presentingViewController
parce que vous ne peut pas se référer à une propriété après que le contrôleur a été rejeté)L'inverse, de conserver tout le code dans
infoController
en mettant lesendMeMail
code dans la réalisation de bloc:mise à jour/modifier
Si vous mettez tout le code dans la réalisation de bloc, vous devez définir mailController de mailComposeDelegate à
presentingVC
, pasself
. Puis de gérer le délégué de la méthode dans la présentation de viewController.mise à jour 2
@Auro a fourni une analyse détaillée de la solution à l'aide d'un délégué de la méthode, et dans ses commentaires sur les points que cela exprime le mieux la séparation des rôles. Le traditionaliste dans me convient, et je ne l'égard
dismissViewController:animated:completion
comme un encombrants et facilement mal compris morceau de l'API.Apple docs ont ceci à dire:
Avis qu'ils ne mentionnent même pas
dismissViewController:animated:completion:
ici, comme si ils n'ont pas beaucoup de respect pour leur propre API.Mais la délégation semble être une question que les gens ont souvent du mal avec: et peut exiger une longue réponse... je pense que c'est une des raisons pour Apple pousse les blocs si dur. Dans les cas où seul le code doit s'exécuter dans un lieu, le modèle de délégué est souvent considéré par les initiés comme trop complexe solution apparemment un problème simple.
Je suppose que la meilleure réponse, si vous voulez apprendre ce genre de choses, est la mise en œuvre de deux manières. Alors vous allez vraiment obtenir une poignée sur les modèles de conception dans le jeu.
À ce sujet,
Après avoir écarté auto viewController, vous ne pouvez pas présenter de vue des contrôleurs de soi.
Puis ce que vous pouvez faire ?
1) appuyez sur le bouton de la méthode,
2) Vous pouvez faire disparaître l'auto viewController, lorsque le mailViewController est rejeté.
Si vous utilisez des story-boards, essayez de vérifier les types de transition que vous utilisez sur votre enchaîne. Vous avez des problèmes en rejetant les couches de viewcontrollers vous la transition vers modal. Cela peut être la source de vos problèmes. Essayez de basculer entre eux pour les pousser à la place. Bien que vous pouvez écrire des délégués à accomplir rejetant viewcontrollers il ne devrait pas être nécessaire. C'est trop compliqué solution. L'Image si vous avez un viewcontroller que les transitions à des dizaines de différents scénarios-maquettes, vous allez avoir des dizaines de délégués contrôle de licenciement? Il semble sous-optimale.
Utiliser ce code
Au lieu de