I have an app that allows the user to send a test email from their iPhone. My app calls a method to activate the compose mail function like this:
-(void)displayComposerSheet
{
//set up a way to cancel the email here
//picker is an instance of MSMailComposeViewController already declared in the .h file
[picker setSubject:#"Test Mail"];
// Set up recipients
// Attach an image to the email
NSString *path = [[NSBundle mainBundle] pathForResource:#"Icon" ofType:#"png"];
NSData *myData = [NSData dataWithContentsOfFile:path];
[picker addAttachmentData:myData mimeType:#"image/png" fileName:#"Icon"];
// Fill out the email body text
NSString *emailBody = #"This is a test mail.";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
NSLog(#"mail is working");
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
emailLabel.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
emailLabel.text = #"Mail sending canceled.";
break;
case MFMailComposeResultSaved:
emailLabel.text = #"Mail saved.";
break;
case MFMailComposeResultSent:
{
emailLabel.text = #"Mail sent.";
NSLog(#"It's away!");
UIAlertView *emailAlertView = [[UIAlertView alloc] initWithTitle:#"Sent!" message:#"Mail sent successfully." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[emailAlertView show];
[self dismissModalViewControllerAnimated:YES];
[self.navigationController popViewControllerAnimated:YES];
}
break;
case MFMailComposeResultFailed:
{
emailLabel.text = #"Mail sending failed.";
}
break;
default:
{
emailLabel.text = #"Mail not sent.";
}
break;
}
}
My problem is that when the compose email function is active, I am unable to come out of this function and return to my app. The only way out of this is by actually going ahead and sending a message. There is a default "cancel" bar button that appears on the top left hand corner of the navigation bar, which when clicked, gives me three options: "delete draft", "save draft", and "cancel". If I select "delete draft", it does nothing except to return me to the compose message screen. Is there a way for me to allow the user to return to the app after starting the compose mail function, but prior to sending it? Is there a way to add extra functionality to the "cancel" bar button to accomplish this?
Thanks in advance to all who reply.
You have to implement MFMessageComposeViewControllerDelegate with the - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result method.
You will dismiss your message view in this method.
EDIT : i confused with MFMailComposeViewControllerDelegate but the purpose is the same as with MFMessageComposeViewControllerDelegate
Take a look at your own code in your ...didFinishWithResult: method:
case MFMailComposeResultCancelled:
emailLabel.text = #"Mail sending canceled.";
break;
case MFMailComposeResultSaved:
emailLabel.text = #"Mail saved.";
break;
case MFMailComposeResultSent:
{
emailLabel.text = #"Mail sent.";
NSLog(#"It's away!");
UIAlertView *emailAlertView = [[UIAlertView alloc] initWithTitle:#"Sent!" message:#"Mail sent successfully." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[emailAlertView show];
[self dismissModalViewControllerAnimated:YES];
[self.navigationController popViewControllerAnimated:YES];
}
When the result is MFMailComposeResultSent you're dismissing the modal view controller and popping the nav stack, which causes the mail compose view controller to go away, and also pops the stack to remove the view controller that presented the compose view controller. When the result is MFMailComposeResultCancelled, however, you just set some label's text. Same for MFMailComposeResultSaved. You need to dismiss the message compose view controller for these cases too if you want the compose view controller to go away when the user cancels or saves.
You should add this method in your view controller
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self becomeFirstResponder];
[self dismissViewControllerAnimated:YES completion:nil];
}
hope this one helps some one.
Set Delegate of MFMailComposeViewController
MFMailComposeViewController *mailcomposer = [[MFMailComposeViewController alloc]init];
mailcomposer.mailComposeDelegate = self;
And Use this Delegate Method
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
Related
I have a view controller "Paircontroller" that presents an MFMessageComposeViewController, as so:
NSArray *recpts = [[NSArray alloc]initWithObjects:phone.text, nil];
MFMessageComposeViewController *mcontr = [[MFMessageComposeViewController alloc]init];
mcontr.body = #"Sign up for our app!";
mcontr.recipients = recpts;
mcontr.subject = #"hey!";
mcontr.delegate = self;
[self presentViewController:mcontr animated:YES completion:^{
}];
this view controller's interface looks as follows:
#interface PairViewController : UIViewController<UITextFieldDelegate,CustomIOS7AlertViewDelegate, UINavigationControllerDelegate, MFMessageComposeViewControllerDelegate>
#end
Within the view-controller's implementation, I have defined the delegate method - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
as follows:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
switch (result) {
case MessageComposeResultCancelled:
NSLog(#"Cancelled");
break;
case MessageComposeResultFailed:
NSLog(#"unknown error sending m");
break;
case MessageComposeResultSent:
NSLog(#"Message sent successfully");
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:^{}];
}
However, the delegate method is not being called (breakpoint not hit, and NSLogs not being hit either).
Can someone help me out on why this is not working?
Thanks!
C
I think the following change should work. MFMessageComposeViewController is a UINavigationController subclass, so in your original code you are setting UINavigationControllerDelegate to self.
mcontr.messageComposeDelegate = self;
EXTRA INFO: I must have asked wrong, I'd like the user to click the button and be redirected to Facebook!
I need to add a visit facebook button called "facebook" as swell in the code below! Right now I just have an ok button.
Also if possible could you help me understand, how I will be able to retrieve user information - e.g I'll ask them to add there email in the textfield, when they press ok then where will I store the email and obtain it, how does that work, and what do I need to read to find out?
Try to add your buttons in otherButtonTitles
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Refresh"
message:#"Are you want to Refresh Data"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Button1",#"Button2",#"Button3",
nil];
As per Duncan's answer you can use delegate and get which button is clicked.so on specific button's tap you can redirect to facebook page using below code.
UIAlertView *info = [[UIAlertView alloc]initWithTitle:#"Yup" message:#"You've won! Like Us on Facebook too" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Facebook", nil];
info.tag = 10;
[info show];
So when the user presses the Facebook button the delegate method alertView:clickedButtonAtIndex will be called so at that time check alert.tag and then check if facebook button is tapped then show another alert.
Your Delegate Method should be
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 10)
{
switch (buttonIndex) {
case 0:
NSLog(#"Cancel");
break;
case 1:
NSLog(#"Facebook");
[self showAlertForRedirect];
break;
default:
break;
}
}
else if (alertView.tag == 20)
{
switch (buttonIndex) {
case 0:
NSLog(#"Cancel");
break;
case 1:
NSLog(#"OK");
[self RedirectNow];
break;
default:
break;
}
}
}
-(void)showAlertForRedirect
{
UIAlertView *info2 = [[UIAlertView alloc]initWithTitle:#"Note" message:#"Would you like to redirect on facebook?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
info2.tag = 20;
[info2 show];
}
-(void)RedirectNow
{
NSURL *fanPageURL = [NSURL URLWithString:#"fb://profile/yourid"];
if (![[UIApplication sharedApplication] openURL: fanPageURL])
{
NSURL *webURL = [NSURL URLWithString:#"https://www.facebook.com/yourpagename"];
[[UIApplication sharedApplication] openURL: webURL];
}
}
As the other poster said, you can add additional buttons by providing button titles in the otherButtonTitles parameter to the initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles: method.
You can set up your alert to have an input field by setting the alertViewStyle property of the button returned by the above method to UIAlertViewStylePlainTextInput
You need to pass in self (your view controller) as the delegate parameter.
Then you need to implement the method alertView:didDismissWithButtonIndex:
In that method, you will get the button index the user selected. You can use the textFieldAtIndex: method to get a pointer to the text field, and get the user-entered text.
I've got two labels in a custom UITableViewCell. Their purpose is to indicate the status of a timing operation on the object represented by the cell.
One label displays a countup timer. The other simply blinks "Timer Sleeping." Their visibility is mutually exclusive (if one is visible, the other is not, and vice versa) according to a switch statement to determine which label is currently visible. Each is driven by a dedicated NSTimer.
Everything works fine--until I do a modal segue to another View Controller (for the purpose of adding another entity or other task) and then return to the original VC via Cancel or Savethrough delegation. Then, regardless of which label had been visible (and updating via its timer) prior to the segue, no label is to be seen. The cell appears blank.
The weird thing is that when I segue to yet another VC via a push segue, then return via the "Home" button, the labels appear, blinking or counting up, just as though nothing had happened. The only obvious difference I can see between the two return methods is that the modal is handled via delegation whereas the push is unwound through a nav controller.
Any ideas? I can supply any relevant code, but didn't know where to start and didn't want to paste all of it.
Thanks!
EDIT for clarification in response to question below:
I'm returning via delegation. Here's the code in the modal:
- (IBAction)saveButton:(UIBarButtonItem *)sender
{
if (self.activityField.text.length > 0)
{
if (self.categoryLabel.text.length < 1)
{
// self.thisActivity.category = #"Uncategorized";
// self.thisActivity.name =self.activityField.text;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No category selected"
message:#"Please select a category or Cancel"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
self.thisCategory.name = self.categoryLabel.text;
self.thisActivity.name = self.activityField.text;
self.thisActivity.category = self.thisCategory.name;
NSLog(#"Category name is %#", self.thisCategory.name);
NSLog(#"Activity name is %#", self.thisActivity.name);
[self.delegate addActivityViewControllerDidSave];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No activity entered"
message:#"Please enter a new activity or Cancel"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (IBAction)cancelButton:(UIBarButtonItem *)sender
{
[self.delegate addActivityViewControllerDidCancel:self.thisActivity];
NSLog(#"delegate is %#",self.delegate);
}
And here's the delegate method implementation code from the original VC:
#pragma mark - AddViewControllerDelegate stuff
-(void) addActivityViewControllerDidSave
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
-(void) addActivityViewControllerDidCancel:(WMDGActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
2nd edit:
Here's the refreshData code:
-(void) refreshData
{
actFRC = [WMDGActivity MR_fetchAllSortedBy:#"category,name"
ascending:YES withPredicate:nil
groupBy:#"category"
delegate:nil];
[self.myTableView reloadData];
}
I've tried calling this method in viewDidLoad, and NOT calling it there. Same results.
UPDATE, 3/26/2014:
OK, I've discovered that if I remove the call to refreshData from my addActivityViewControllerDidCancel method, the labels work fine. They likewise work fine if I remove the same line from addActivityViewControllerDidSave. Unfortunately, this prevents newly added items from appearing in the HomeViewController table view until the app is relaunched.
Here is my current code for the cancel and save methods:
-(void) addActivityViewControllerDidSave
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
-(void) addActivityViewControllerDidCancel:(WMDGActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
// [self refreshData];
}
I view this as a temporary, or interim, fix. Sure would be grateful for a real cure.
Thanks!
I am trying to allow the player to share their score by SMS when the game is over.
I have imported the framework in to my project. Imported in the my viewController.h file.
here is my viewController.h file
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#import <MessageUI/MessageUI.h>
#interface myViewController : UIViewController <MFMessageComposeViewControllerDelegate> {
}
#end
I also tried to import into MyScene.h like so:
#import <MessageUI/MessageUI.h>
#interface MyScene : SKScene <MFMessageComposeViewControllerDelegate> {
}
When I want to show the SMS share, I use this code in my MyScene.m file
MFMessageComposeViewController *textComposer = [[MFMessageComposeViewController alloc] init];
[textComposer setMessageComposeDelegate:self];
if ([MFMessageComposeViewController canSendText]) {
[textComposer setRecipients:[NSArray arrayWithObject:nil]];
[textComposer setBody:#"Happy Happy Joy Joy!"];
[self presentViewController:textComposer animated:YES completion:NULL];
} else {
NSLog(#"Cant send text!");
}
But on this line
[self presentViewController:textComposer animated:YES completion:NULL];
I get an "No visible #interface for 'MyScene' declares the selector 'presentViewController:animated:completion:'" error.
I have tried to search for the last couple hours. Try god knows how many variations and examples from other posts/tutorials(which was good to learn a few things unrelated to this). Nothing seems the work. I starting to run out of hair to pull out. So any help would be great. I am sure for some of you Gurus here this should be a walk in the park. Thanks.
EDIT: I am not using storyboard, or the view controller for buttons/menu/game play etc...hence why I am not able to call the function from within the viewController itself.
EDIT:
So I tried what Paulw11 suggested in his link. Now I have the following errors.
in myViewController
MyScene.MyViewController = self;
I get a "Property 'MyViewController' not found on object of type 'MyScene'" error
also in MyScene.m
- (void)sendToController
{
NSLog(#"ok");
// use the already-created spriteViewController
[_MyViewController sendSMS];
}
[_MyViewController sendSMS]; line I get an "No visible #interface for 'MyViewController' declares the selector 'SendSMS'"
EDIT 2: *EDIT 2:* EDIT 2: *EDIT 2:*
I got it to open up the SMS. Small problem, it does not allow me to dismiss it /cancel.
Here is my sendSMS code:
-(void) sendSMS {
MFMessageComposeViewController *textComposer = [[MFMessageComposeViewController alloc] init];
[textComposer setMessageComposeDelegate:self];
if ([MFMessageComposeViewController canSendText]) {
[textComposer setRecipients:[NSArray arrayWithObject:#" "]];
NSString *body = [NSString stringWithFormat:#"Happy Day!: %i. ", _score];
[textComposer setBody:body];
UIViewController *vc = self.view.window.rootViewController;
[vc presentViewController: textComposer animated: YES completion:nil];
} else {
NSLog(#"Cant send text!");
}
}
Here is my dismiss code:
-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
UIViewController *vc = self.view.window.rootViewController;
[vc dismissViewControllerAnimated:YES completion:NULL];
}
EDIT 3
The following code gives me the NSLog at the correct times, but does not dismiss the window.
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
{
UIViewController *vc = self.view.window.rootViewController;
// Notifies users about errors associated with the interface
switch (result)
{
case MessageComposeResultCancelled:
NSLog(#"Result: SMS sending canceled");
break;
case MessageComposeResultSent:
NSLog(#"Result: SMS sent");
break;
case MessageComposeResultFailed:
NSLog(#"Result: SMS sending failed");
break;
default:
NSLog(#"Result: SMS not sent");
break;
}
[vc dismissViewControllerAnimated:YES completion:NULL];
}
If you refer to the MFMessageComposeViewController Class Reference you will see that you need to present it modally using presentModalViewController:animated:. You are also responsible for dismissing it via your delegate object once you are done.
I suggest you have a look at the Message Composer sample code for an example of using the MFMessageComposeViewController class.
UPDATE
You can just dismiss the view controller that was passed to your delegate method -
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
{
// Notifies users about errors associated with the interface
switch (result)
{
case MessageComposeResultCancelled:
NSLog(#"Result: SMS sending canceled");
break;
case MessageComposeResultSent:
NSLog(#"Result: SMS sent");
break;
case MessageComposeResultFailed:
NSLog(#"Result: SMS sending failed");
break;
default:
NSLog(#"Result: SMS not sent");
break;
}
[controller dismissViewControllerAnimated:YES completion:NULL];
}
I have created an application that uses the SMS and after the user clicks the sms button it opens up with my number already in and no message (thats their job). But when it loads up the sms message page it set the curser thing is up where the recipients are not where the message is. To explain that better, after the sms loads if they were to just start typing they would be adding another person to send the message to, not typing the message. For example if I would like to load up to a specific row on my UIPicker on startup I would:
[picker selectRow:3 inComponent:0 animated:NO];
sms load up:
- (IBAction)sms {
MFMessageComposeViewController *textComposer = [[MFMessageComposeViewController alloc] init];
[textComposer setMessageComposeDelegate:self];
if ([MFMessageComposeViewController canSendText]) {
[textComposer setRecipients:[NSArray arrayWithObjects: #"support#nicmacengineering.com", nil]];
[textComposer setBody:#""];
[self presentViewController:textComposer animated:YES completion:NULL];
} else {
NSLog(#"Can't Open Text");
}
}
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
switch (result) {
case MessageComposeResultCancelled:
NSLog(#"Cancelled");
break;
case MessageComposeResultFailed:
break;
case MessageComposeResultSent:
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
First, your question is fairly hard to understand. Here's my impression of it:
Can I set the cursor to the message field by default in an SMS controller?
And the answer is:
No.
Since it is an Apple framework, with no public method to switch fields (here's the class reference).
Because of this, you won't be able to automatically set the position of the cursor.