I have a UITableViewController presenting a list of contacts, when the user selects a row, it'll show a UIActionSheet to ask the user an action (call, send sms...).
The user selects an action, and that first UIActionSheet will show another UIActionSheet which contains phone numbers.
The user selects a phone number, and this should show the SMS message composer.
The problem is that when the user selects a phone number, the message composer view doesn't show (just a black screen), and I receive the MessageComposeResultCancelled in the MFMessageComposeViewController's didFinishWithResult.
Which generates this warning "Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!"
How can I correctly call and show the SMS message composer?
(this works perfectly if I call it directly when the user selects a row in the list with didSelectRowAtIndexPath)
Here's some code :
1- call to first UIActionSheet in didSelectRowAtIndexPath method :
UIActionSheet *popupQuery;
...
[popupQuery showInView:self.view];
2- call to second UIActionSheet in clickedButtonAtIndex method :
UIActionSheet *popupQuery2;
...
[popupQuery showInView:self.view];
3- from the same method, call to message composer :
[self sendSMS:#"" recipientList:[phoneNumbers objectAtIndex:buttonIndex]];
the method that shows message composer :
(void)sendSMS:(NSString *)bodyOfMessage recipientList:(NSArray *)recipients
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText])
{
controller.body = bodyOfMessage;
controller.recipients = recipients;
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}
solution found here : MFMessageComposeViewController shows blank/white screen
controller.recipients = [NSArray arrayWithObject:theRecipients];
theRecipients was an array containing only one element (the phone number selected)
As you don't want to try showing two modal controls in the same time, use actionSheet:didDismissWithButtonIndex: delegate method so that action sheet is hidden when you start to show messaging controller.
The following code shows composer which is not cancelled automatically.
I can see 0 at log which is the value of MessageComposeResultCancelled, only when I press Cancel button. Are you trying to make a hack by pressing send button automatically ?
MFMessageComposeViewController.h
enum MessageComposeResult {
MessageComposeResultCancelled, //0
MessageComposeResultSent, //1
MessageComposeResultFailed //2
};
MyViewController.m
-(IBAction)onButtonPressed:(id)sender {
UIActionSheet * sheet = [[UIActionSheet alloc] initWithTitle:#"Title"
delegate:self
cancelButtonTitle:#"Go out"
destructiveButtonTitle:#"Show message composer"
otherButtonTitles:nil, nil];
[sheet showInView:self.view];
}
-(void) actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText])
{
controller.body = #"body";
// controller.recipients = recipients;
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}
-(void) messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
NSLog(#"%d", result);
[controller dismissModalViewControllerAnimated:YES];
}
Related
I am using MFMailComposeViewController in my application to compose a feedback E-Mail. The MFMailComposeViewController gets displayed, but can't be closed.
Method used to open the MFMailComposeViewController modal window:
-(IBAction) feedbackBtnClicked:(id)sender {
// Dismiss the Old View Controller
[self dismissViewControllerAnimated:NO completion:NULL];
// Present the New View Controller
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
mail.mailComposeDelegate = self;
[mail setSubject:#"Sample Subject"];
[mail setMessageBody:#"Here is some main text in the email!" isHTML:NO];
[mail setToRecipients:#[#"example#mail.com"]];
[self presentViewController:mail animated:YES completion:NULL];
}
else
{
NSLog(#"This device cannot send email");
}
}
Here is what happens, when clicking on the buttons:
Senden (Send) - The E-Mail gets sent, but the modal window stays open; clicking on that button multiple times results in sending multiple E-Mails without the modal window ever getting closed.
Abbrechen (Cancel) - Nothing happens
How to dismiss make sure the MFMailComposeViewController gets dismissed after clicking on those buttons?
You need to implement the MFMailComposeViewControllerDelegate method mailComposeController:didFinishWithResult:error:, and dismiss the mail view controller…
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
In my code I want to open one view controller as presentviewcontroller using actionsheet. but when i click on the button of actionsheet view is not coming but it's code is executing.
Here is the code invoking the action sheet:
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#""
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Print Full Report",#"Print Only Selected Questions", nil];
//Creating Attributed String with System Font size of 30.0f
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:#"Print Options" attributes:#{NSFontAttributeName: [UIFont systemFontOfSize:20.0f] , NSForegroundColorAttributeName : [UIColor grayColor]}];
//Accessing the Alert View Controller property from Action Sheet
UIAlertController *alertController = [actionSheet valueForKey:#"_alertController"];
//Setting Attributed Title property of Alert View Controller
[alertController setValue:attrString forKey:#"_attributedTitle"];
[actionSheet showInView:self.view];
actionSheet.tag = 100;
And here are the delegate and associated methods:
- (void)actionSheet:(UIActionSheet *)popup clickedButtonAtIndex:(NSInteger)buttonIndex {
// tag 1 = save options. 2 = clear options
switch (buttonIndex) {
case 0:
[popup dismissWithClickedButtonIndex:0 animated:YES];
pdfFlag=1;
[self printReportAction];
break;
case 1:
[popup dismissWithClickedButtonIndex:1 animated:YES];
pdfFlag=2;
[self printReportAction];
break;
}
}
-(void)printReportAction{
[self presentViewController:previewer animated:YES completion:nil];
}
did you initialized controller to present?
if so, checked VC for present not nil
remove these calls:
[popup dismissWithClickedButtonIndex:0 animated:YES];
There could be several reasons why the code isn't working. However, ActionSheets were deprecated in iOS 8.3. I would suggest using UIAlertController instead. Using an UIAlertController allows you to use blocks which makes tracking how issues much easier and cleaner.
I have mocked up a sample project that recreates what you are trying to accomplish. https://github.com/andyast/ActionSheetTest
UIAlertView delayed or not showing up when pass another view. Any help would be greatly appreciated.
-(void)viewDidLoad{
levelContentController = [[UIAlertView alloc] initWithTitle:#""
message:#"Loading...
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
}
-(void)passToTestView:(id)sender{
[levelContentController show];
ViewController *viewController = [[ViewController alloc]init];
clickedLevelId = [[NSString alloc] init];
clickedLevelId = [testIdStringArray objectAtIndex:[sender tag]-1];
[viewController sendIndexMethod:sendIndex];
[viewController testCompletedArrayMethod:arrayOfCompletedTest];
[viewController parseTestURL:buttonTag getTestIdString:clickedLevelId];
viewController.viewSoundCheck = _levelSoundCheck;
[self presentViewController:viewController animated:YES completion:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[levelContentController dismissWithClickedButtonIndex:0 animated:YES];
}
The above code has some problems.
When passToTestView: selector is called, it'll try to present the alertView. But within the same method you are trying to present another view controller.
This will in turn call viewWillDisappear: where you are hiding the alertView.
It's recommended that if you want to present the alertView while displaying ViewController, create and display UIAlertView instance in the ViewController class's viewDidLoad or viewWillAppear:. Do not initialise and display it in this viewController.
To make the UIAlertView appear, you should call:
[contentLoadingController show];
Note that UIAlertView is deprecated in iOS9, and you should use UIAlertController.
I have a View Controller which displays a table view. The VC calls another VC to display the send SMS view to the user, the code for this SMS VC is:
- (void) sendSMSWithBody: (NSString*) body andRecipients: (NSArray*) recipients
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText])
{
controller.messageComposeDelegate = self;
controller.body = body;
controller.recipients = recipients;
[[UIApplication sharedApplication].delegate.window.rootViewController addChildViewController:self];
[self presentModalViewController:controller animated:YES];
}
}
- (void) messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication].delegate.window.rootViewController removeFromParentViewController];
}
(I know the call to sharedApplication is a bit hacky, but it will suffice for now. the rootViewController is a UINavigationController which has its root controller set to the table view controller)
I am invoking the SMS VC from the table VC like so:
- (void ) viewDidAppear:(BOOL)animated
{
static BOOL presentedSMSVC = NO;
if (!presentedSMSVC)
{
SendSMSController *sendSMS = [[SendSMSController alloc] init];
[sendSMS sendSMSWithBody:#"body"
andRecipients:[NSArray arrayWithObject:#"123456789"]];
presentedRegisterVC = YES;
}
}
The problem is that after the user sends the SMS the table view cells are not displaying.
I thought maybe I need to refresh the view/table so I added a protocol callback from the 2nd VC to the first which gets invoked when the user sends the SMS, and then within the callback call [self.tableView reloadData] But it made no difference.
So I got rid of the intermediary class and edited the table view to display the SMS view directly like this:
- (void ) viewDidAppear:(BOOL)animated
{
static BOOL presentedRegisterVC = NO;
if (!presentedRegisterVC)
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText])
{
controller.messageComposeDelegate = self;
controller.body = #"body";
controller.recipients = [NSArray arrayWithObject:#"12345678"];
[self presentModalViewController:controller animated:NO];
}
}
}
- (void) messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:NO];
}
But now the MFMessageComposeViewController doesn't dismiss (although messageComposeViewController:didFinishWithResult: does get called)
What is the problem with both approaches? Thanks
For the second variant, I changed to:
[self presentViewController: controller animated: YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
And that worked, haven't tried applying to the first method.
I faced a similar UI issue.
My case was: The controller, let's say controller A, in which I had written the code to present and dismiss the MFMessageComposeController, was not being used directly as the active controller rather I was using A.view as a subview over another controller, say controller B. So writing the following was distorting the view:
[self presentViewController:composeVC animated:YES completion:nil];
But then writing the following solved my issue:
[self.customTabbarNavigation presentViewController:composeVC animated:YES completion:nil];
The customTabbarNavigation, was the controller B, ans was actually the navigation controller which was active when controller A's view was visible.
Same change had to be made for dismissing the composeVC.
My app has a common class that displays an actionSheet whenever "Contact Us" is clicked from any one of the many NIBs.
If the user chooses "Email Us" from the actionSheet popup, I'd like to call the email methods from the same common class. After researching I implemented this:
-(void)SendEmail {
rootViewController = (UIViewController*)
[(AppDelegate*)[[UIApplication sharedApplication] delegate] viewController];
// compose
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = rootViewController;
//format message
NSArray *recipientsArray = [[NSArray alloc] initWithObjects:#"support#somename.com", nil];
[controller setToRecipients:recipientsArray];
[controller setSubject:[NSString stringWithFormat:#"A question about %#",string]];
[controller setMessageBody:outputMutString isHTML:YES];
//send
if (controller) [rootViewController presentModalViewController:controller animated:YES];
}
//didFinishWithResult
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error;{
if (result == MFMailComposeResultSent) {
}
[rootViewController dismissModalViewControllerAnimated:YES];
}
This will launch a new email, however:
The didFinishWithResult doesn't work as the modal view is not removed either after sending the email or pressing the Cancel button
I am getting this warning: assigning to 'id' from incompatible type 'UIViewController *__strong'
controller.mailComposeDelegate = rootViewController;
Help appreciated.
You need to set your rootViewController as adopting the delegate MFMailComposeViewControllerDelegate.
i.e. in your RootViewController.h file, add that part to the interface declaration so that it looks similar to:
#interface RootViewController : UIViewController <MFMailComposeViewControllerDelegate>