I have a some kind of action sheet UIView which calls MFMailComposeViewController after tapping a button in it, the MFMailComposeViewController gets called and presented successfully, but it doesn't dismiss when the I tap Cancel and sometimes crashes, I know this is a known problem, but I have tried all the known fixes but it doesn't work for me. That's my code:
SendFeedback.h:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#interface SendFeedback : UIView <UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>
//Useless code to the problem.
#property (nonatomic, retain) MFMailComposeViewController *feedBackComposer;
#end
SendFeedback.m:
- (void)baseInit
{
//Useless code to the problem.
feedBackComposer = [[MFMailComposeViewController alloc] init];
[feedBackComposer setMailComposeDelegate:self];
[feedBackComposer setToRecipients:[NSArray arrayWithObject:#"info#getibox.com"]];
[feedBackComposer setMessageBody:#"" isHTML:NO];
[feedBackComposer setSubject:#"What I Love About iBox"];
}
And to call the composer:
- (void)sendFeedbackComposer
{
[self.window.rootViewController presentViewController:feedBackComposer animated:YES completion:nil];
}
To dismiss it:
- (void)mailComposeController:(MFMailComposeViewController *)feedBackComposer didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
//This method doesn't get called.
[self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Error: %#", error);
}
EDIT: So, all the answers provided in this question were correct, and it was all my bad. What I wanted to do is: I had a UINavigationController which includes a UITableView one of the cells in that view should trigger an action sheet which is a UITableView by adding it as a subview, just like the previous one, this view also includes cells and one of them will do an action and it is calling an MFMailComposeViewController, which gets called but doesn't dismiss successfully even though I had its delegate set up and all the methods correct, the cause of the problem was the way of calling the MFMailComposeController, I first removed from super view that little UITableView then presented the MFMailComposeController, so when I dismissed the mail composer it crashed without even giving a result, which made me confuse the cause of the crash with the delegate method, fool me.
Here's the code:
- (void)removeView
{
if (self) {
[UIView animateWithDuration:0.3
animations:^{backgroundView.alpha = 0;}
completion:^(BOOL finished){
[UIView animateWithDuration:.3
animations:^{self.frame = CGRectMake(0, 568, 320, 568);}
completion:^(BOOL finished){[self removeFromSuperview];}];
}];
}
}
- (void)sendFeedbackComposer
{
feedBackComposer = [[MFMailComposeViewController alloc] init];
[feedBackComposer setMailComposeDelegate:self];
[feedBackComposer setToRecipients:[NSArray arrayWithObject:#"info#getibox.com"]];
[feedBackComposer setMessageBody:#"" isHTML:NO];
[feedBackComposer setSubject:#"What I Love About iBox"];
[self.window.rootViewController presentViewController:self.feedBackComposer animated:YES completion:nil];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case 2: //That's the index of the MailComposer caller.
[self removeView];
[self sendFeedbackComposer];
break;
case 6:
[self removeView];
break;
default:
break;
}
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[feedBackComposer.presentingViewController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Error: %#", error);
}
Thanks to Stefan Atanasov, Jim, and Vitaly S.
Are you sure that delegate method isn't called? I made a test and it's called, but to dismiss mail composer use such code:
[feedBackComposer dismissViewControllerAnimated: YES completion: nil];
Also it's really strange to implement delegates in view implementation, not in view controller
To add something to Vitaly S.'s answer (due to lack of reputation I can't comment directly on it, sorry) - the delegate method is called, so the problem is the dismissal. You can try this:
[feedBackComposer.presentingViewController dismissViewControllerAnimated: YES completion: nil];
The delegate methods need to be called from the viewController, not from within the UIView.
Your view controller that calls the UIView will have your delegates
<UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>
within it's header file.
You need to make a delegate method to pass information from the UIView to the controller, which will in turn call the mail and table delegate methods.
Here is a link to a question that demonstrates how to use a delegate protocol to trigger a method in the view controller from the UIView.
Trigger a method in UIViewController from its View
Hope this helps, Jim
you need to check is it device is configure to send mail by checking MFMailComposeViewController is avail to respond or not.
if([MFMailComposeViewController canSendMail]){
//your code
}
Related
I have got two view controllers. Im trying to pass data to the previous viewcontroller
I have the following code in my second view controller CEPeoplePickerNavigationController
#class CEPeoplePickerNavigationController;
#protocol CEPeoplePickerNavigationControllerDelegate <NSObject>
- (void)previousViewController:(CEPeoplePickerNavigationController *)controller itemToSend:(NSString *)item;
#end
#interface CEPeoplePickerNavigationController : UIViewController <UITableViewDelegate,UITableViewDataSource>{
}
#property (nonatomic, retain) id < CEPeoplePickerNavigationControllerDelegate> peoplePickerDelegate;
#end
When the user clicks the done button, following code will be exectied
- (void)doneAction:(id)sender
{
[self.peoplePickerDelegate previousViewController:self itemToSend:#"From Previous VC"];
[self dismissViewControllerAnimated:YES completion:nil];
}
In my first view controller, I have the following interface in header file and I have ofcourse implemented the previousViewController method in my first view controller where the data has to be received
#interface CallViewViewController : UIViewController<CEPeoplePickerNavigationControllerDelegate>
#end
When I move from the first view controller to the second view controller, Im using the following code.
CEPeoplePickerNavigationController *nextVc = [[CEPeoplePickerNavigationController alloc] init];
nextVc.peoplePickerDelegate = self;
[self presentViewController:nextVc animated:YES completion:nil];
But when the user clicks the done button from the second view controller, Im not receiving any callback in my first view controller. why so?
I have implemented the interface as following,
- (void)previousViewController:(CEPeoplePickerNavigationController *)controller itemToSend:(NSString *)item
{
NSLog(#"from CEPeoplePickerNavigationController %#",item);
}
UPDATE:
Following code works
if ([[CallViewViewController new] respondsToSelector:#selector(previousViewController:item:)]) {
[self.viewCrtrlDelegate previousViewController:self item:#"Here I am"];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
NSLog(#"Your delegate was properly set");
}
But if I try it by following way, it is not working
if ([[self.viewCrtrlDelegate respondsToSelector:#selector(previousViewController:item:)]) {
[self.viewCrtrlDelegate previousViewController:self item:#"Here I am"];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
NSLog(#"Your delegate was properly set");
}
This is how Im instantiating the view controller.
CEPeoplePickerNavigationController *nextVc = [[CEPeoplePickerNavigationController alloc] init];
nextVc.viewCrtrlDelegate = self;
[self presentViewController:nextVc animated:YES completion:nil];
Your code seems absolutely correct but to get around all the possibilities.
Can you check whether your done button action has a check to know if the delegate methods is available or not in that class?
if ([self.viewCrtrlDelegate respondsToSelector:#selector(previousViewController:item:)]) {
[self.viewCrtrlDelegate previousViewController:self item:#"Here I am"];
[self dismissViewControllerAnimated:YES completion:nil];
}
else{
NSLog(#"Your delegate was properly set");
}
I am working on implementing Apple Pay for my Application. While I have everything mostly figured out, I am not able to dismiss the PKPaymentAuthorizationViewController that authenticates.
Here is my code..
-(void) viewDidAppear:(BOOL)animated {
// request is initialized here.
paymentPane = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
//paymentPane is not nil.
paymentPane.delegate = self;
[self presentViewController:paymentPane animated:TRUE completion:nil];
}
The above function is called and successfully presents the Apple Pay View Controller to authenticate the payment. I have implemented the following methods from the delegate as follows:
-(void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion {
NSLog(#"%#", [payment.token description]);
completion(PKPaymentAuthorizationStatusSuccess);
}
Ideally it hits the didAuthorizePayment first, where we authenticate the payment, and pass success if its successful, then the paymentAuthorizationViewControllerDidFinish is called and that is used to complete transaction and hide the Apple View Controller. I put breakpoints in there and it hits both functions, but the ViewController doesn't go away. It doesn't go even if you tap the Cancel button inside Apple Pay View.
My class declaration is as follows and does implement the required delegates.
#interface ApplePayManager : UIViewController<PKPaymentAuthorizationViewControllerDelegate, UIAlertViewDelegate>
Any ideas on what I am doing wrong? Why is the view controller not dismissing?
Lastly, I am a bit new to iOS. So I'd appreciate guides and/or links to clarify my doubts!
Already looked at:
http://www.raywenderlich.com/87300/apple-pay-tutorial
https://dzone.com/articles/integrating-your-ios-app-apple
This worked. My teammate found out this solution. Turns out that the ViewController we presented the ApplePay View on wasn't the rootVC. So, switching it to rootVC worked.
UIViewController *rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
[rootViewController presentViewController:paymentPane animated:TRUE completion:nil];
Really simple question i think.
i have a main view and a popover view.
i am trying to make a custom delegate which will enable me to close the popover view at certain times. My code is posted below. The real simple issue i am having is my code dosnt appear to be entering the delegate code. Any ideas as to why? It builds and runs but nothing appears to happen, i have put NSLog statments, the popover nslog appears but the function in
mainview dismissPopover does nothing.
Mainview.h
#interface MainScreen : UIViewController<DismissPopoverDelegate>
Mainview.m
- (void) dismissPopover:(NSNumber *)dataa
{ /* Dismiss you popover here and process data */
[popoverController dismissPopoverAnimated:YES];
NSLog(#"OLOLO");
}
Popover.h
#protocol DismissPopoverDelegate
- (void) dismissPopover:(NSNumber *)yourDataToTransfer;
#end
#interface SelectAgePopOver : UIViewController<UITableViewDataSource,
UITableViewDelegate,UIPopoverControllerDelegate>{
NSArray *items;
id<DismissPopoverDelegate> delegate;
}
#property (nonatomic, assign) id<DismissPopoverDelegate> delegate;
Popover.m
[self.delegate dismissPopover:selrow];
where i want the delegate called.
Thanks
the popover view is called by the following method in main view.m
controller = [[SelectAgePopOver alloc] initWithNibName:#"SelectAgePopOver" bundle:nil];
popoverController = [[UIPopoverController alloc] initWithContentViewController:controller];
[popoverController setDelegate:self];
popoverController.popoverContentSize = CGSizeMake(250, 294);
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
CGRect popRect = CGRectMake((self.AgeRangeTextField.frame.origin.x+50),
(self.AgeRangeTextField.frame.origin.y+50),
(self.AgeRangeTextField.frame.size.width),
(self.AgeRangeTextField.frame.size.height));
[popoverController presentPopoverFromRect:popRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
On where you instantiate the instance of the SelectAgePopOver, you need to set the delegate of the SelectAgePopOver instance to the MainScreen (self) in the Mainview.m, for example:
controller = [[SelectAgePopOver alloc] initWithNibName:#"SelectAgePopOver" bundle:nil];
;
controller.delegate = self;
Please try to set the controller delegate as shown above.
In the SelectAgePopOver.h class file, you do not need to set UIPopOverControllerDelegate though.
I'm having trouble with removing a modal view.
I want to show (after pressing a button) a my own SendMailViewController which it self shows a MFMailComposeViewController. Then and after pressing cancel of send, in my own SendMailView controller in didFinishWithResult i do a [self dismissModalViewControllerAnimated:YES] and that works. The MFMailComposeView goes away.
But then the screen stays black....it think i also have to remove my SendMailViewController from it's parent. That's where i pushed the button...even after [self removeFromParentViewController] it still stays black...
Where do i go wrong?
And yes i would like the extra viewcontroller (SendMailViewController) because that controller will become the delegate of MFMailComposeViewController. Otherwise my caller (controller with the button) get's to much responsibility. Or do i also go wrong here?
Thanks,
/jr00n
- (IBAction)tapExportButton:(id)sender
{
SendMailViewController *sendMailController = [[SendMailViewController alloc]init];
[self presentViewController:sendMailController animated:YES completion:^() {[sendMailController openMailDialog];}];
[sendMailController release];
}
SendMailViewController:
- (void)openMailDialog
{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
...
[self presentModalViewController:mailer animated:YES];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
....
// Remove the mail view
// first i did this:
// [self dismissModalViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:^{[self removeFromParentViewController];}];
}
The problem is with the [self dismissViewControllerAnimated:YES completion:^{[self removeFromParentViewController];}]; in your didFinishWithResult method.
Remove that line and add the following line,
[controller dismissViewControllerAnimated:YES completion:^{[self dismissViewControllerAnimated:YES completion:nil]}];
That make sure we dismiss the controller after dismissing the MailController
I present MFMailComposeViewController controller and set it delegate - everything works as expected with iOS 5 but the delegate method (mailComposeController:didFinishWithResult:error:) is not called in iOS6.
Here are code snippets:
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:<text>];
[controller setMessageBody:<text> isHTML:NO];
[self presentViewController:controller animated:YES completion:nil];
And the following delegate method is not called in iOS6, though the controller is successfully dismissed after Cancel or Done button is pressed:
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
if (error != nil) {
NSLog(#"An error occurred while sending e-mail. %#, %#", error, [error userInfo]);
}
NSLog(#"done with e-mail");
[self dismissViewControllerAnimated:YES completion:nil];
}
Any advice will be greatly appreciated! Thank you in advance.
EDIT: Method viewWillAppear: of my controller presenting mailComposeController is not called either! Can it be a clue?
The question was incorrect, as I actually used UIActivityViewController for data sharing in iOS6 and did not create/present MFMailComposeViewController. That is why I did not see the delegate method triggered.
I have an implementation working on iOS6 and got some issues as well, werid as it sounds and dont know if it can help in your case but I changed 2 things from my iOS 5 implementation instead of using
controller.mailComposeDelegate = self;
I used
[controller setMailComposeDelegate:self];
also, I was missing the UINavigationControllerDelegate protocol