I have a button that call a MFMailComposeViewController. Sometimes, when I click "delete draft", the app crashes but sometimes it correctly dismiss the view. I can' understand why. Here is my code:
- (IBAction)openEmail:(id)sender {
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
composer.mailComposeDelegate = (id)self;
NSArray *myEmail = [[NSArray alloc] initWithObjects:#"me#gmail.com", nil];
[composer setToRecipients:myEmail];
[self presentViewController:composer animated:YES completion:nil];
[[composer navigationBar] setTintColor:[UIColor colorWithRed:0.843 green:0.435 blue:0.435 alpha:1]];
}
else {
}
}
and this method:
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved");
break;
case MFMailComposeResultSent:
NSLog(#"Mail send");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail failed");
break;
default:
NSLog(#"Mail not sent.");
break;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Can anyone help me?
I used to experience this as well, and the potential problematic area in your code may be this line:
MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
It's likely that by the time MFMailComposeViewControllerDelegate methods are called, your composer object is deallocated. Instead, try initiating MFMailComposeViewController on a strong property, like so:
self.composer = [MFMailComposeViewController new];
You can set self.composer to nil once you have acted on the delegate methods to release the MFMailComposeViewController.
Have you tried:
[self presentModalViewController:_picker animated:YES];
Notice 'MODAL'?
With also:
[self dismissModalViewControllerAnimated:YES];
Related
My app crashes when I try to perform sent or cancel button actions in MFMailComposeViewController.
here is my code.
I have imported message framework and added delegates in .h file.
NSString *emailTitle = #"Test Email";
NSString *messageBody = #"Welcome Guest";
NSArray *recipentsArray = [[NSArray alloc]initWithObjects:#"xxx#gmail.com", nil];
[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundColor:nil];
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setMessageBody:messageBody isHTML:NO];
[mc setToRecipients:recipentsArray];
[self presentViewController:mc animated:YES completion:NULL];(void) mailComposeController:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved");
break;
case MFMailComposeResultSent:
NSLog(#"Mail sent");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail sent failure: %#", [error localizedDescription]);
break;
default:
break;
}
// Close the Mail Interface
[self dismissViewControllerAnimated:YES completion:NULL];
}
This is how my mf mail composer looks like :----
Just make the MFMailComposeViewController *mc in global.
I mean declare it outside this method. It's crashing because at the end of method Your mc gets deallocated.
Interface
#interface Demo()
{
MFMailComposeViewController *mc;
}
#end
Implementation
-(void)ShareViaEmail {
objMailComposeController = [[MFMailComposeViewController alloc] init];
objMailComposeController.mailComposeDelegate = self;
if ([MFMailComposeViewController canSendMail]) {
[objMailComposeController setSubject:#"Hello"];
[objMailComposeController setMessageBody:#"This is Body of Message" isHTML:NO];
NSData *ImageData = [NSData dataWithContentsOfFile:self.aStrSourceName];
NSString *mimeType;
if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"Image"]) {
mimeType = #"image/png";
}
else if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"PDF"]) {
mimeType = #"application/pdf";
} else if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"Audio"]) {
mimeType = #"audio/mpeg";
} else if ([[self CheckExtensionOfURL:self.aStrSourceName]isEqualToString:#"Video"]) {
mimeType = #"video/mp4";
}
[objMailComposeController addAttachmentData:ImageData mimeType:mimeType fileName:#"attachement"];
}
[self.navigationController presentViewController:objMailComposeController animated:YES completion:Nil];
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
switch (result) {
case MFMailComposeResultCancelled:
[self ShowAlertView:kMsgMailCancelled];
break;
case MFMailComposeResultFailed:
[self ShowAlertView:kMsgMailFailed];
break;
case MFMailComposeResultSaved:
[self ShowAlertView:kMsgMailSaved];
break;
case MFMailComposeResultSent:
[self ShowAlertView:kMsgSent];
break;
default:
break;
}
// CHECK OUT THIS, THIS MIGHT BE IN YOUR CASE
[self.navigationController dismissViewControllerAnimated:controller completion:nil];
}
I am implementing in-app purchase in a Mac app using the following code.
#implementation AppStoreObserver
-(id) init {
self = [super init];
if (self) {
_products = [[NSMutableArray alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
-(void)dealloc {
[_products release];
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[super dealloc];
}
#pragma mark - Query products
-(void)loadStoreForProducts:(NSArray *)productIds {
SKProductsRequest *productRequest = [[[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIds]] autorelease];
productRequest.delegate = self;
[productRequest start];
}
#pragma mark - Product Delegate
//Got product info
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
[_products removeAllObjects];
for (SKProduct *_product in response.products) {
[_products addObject:_product];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationStoreManagerProductsReceivedInvalid
object:nil
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:response.invalidProductIdentifiers, #"invalidProductIdentifiers", _products, #"products", nil]];
}
#pragma mark - Purchase
-(void) triggerPurchase:(SKProduct *) product {
[[SKPaymentQueue defaultQueue] addPayment:[SKPayment paymentWithProduct:product]];
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
- (void)purchaseProduct:(NSString *)productId
{
if([self canMakePurchases]){
for (SKProduct *_product in _products) {
if ([_product.productIdentifier isEqualToString:productId]) {
[self triggerPurchase:_product];
break;
}
}
}
}
#pragma mark - Payment Queue observers
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction* transaction in transactions)
{
//NSLog(#"%d", transaction.transactionState);
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
NSLog(#"Purchased");
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Error: %#", transaction.error);
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(#"Restored");
[self restoreTransaction:transaction];
break;
default:
break;
}
}
}
#pragma mark - Custom handlers
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
NSLog(#"restore transaction %# %#",transaction.transactionIdentifier , transaction.originalTransaction);
[self finishTransaction:transaction wasSuccessful:YES];
}
-(void) restoreCompletedTransactions {
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
[self finishTransaction:transaction wasSuccessful:YES];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
// error!
[self finishTransaction:transaction wasSuccessful:NO];
}
else
{
// this is fine, the user just cancelled, so don’t notify
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
return;
}
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle:#"OK"];
[alert setMessageText:#"Alert"];
[alert setInformativeText:#"In-App Purchase Failed"];
[alert setAlertStyle:NSWarningAlertStyle];
[alert runModal];
}
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, #"transaction" , nil];
if (wasSuccessful) {
// send out a notification that we’ve finished the transaction
} else {
NSLog(#"user cancelled");
}
}
#end
I am able to retrieve SKProduct successfully but as soon as I purchase a product using a test account the process halts without failing. The SKPaymentTransactionStatePurchasing state is reached but nothing happens afterwards. Even the purchase confirmation dialog is not presented.
Once I stop and re-run the app the last transaction is completed successfully but as soon as I try to make another transaction the same thing happens. I have spent several days trying to identify the cause without success. I hope someone here is able to identify the problem. Thanks for your time.
I am using FBFriendPickerViewController to load friends after user signs in. However, an empty table view is being loaded. The friends of the user from fb are not showing up.
Heres the code.
- (IBAction)inviteButtonTouchHandler:(id)sender {
if (!_friendPickerController) {
_friendPickerController = [[FBFriendPickerViewController alloc] initWithNibName:nil bundle:nil];
_friendPickerController.delegate = self;
_friendPickerController.title = #"Select friends";
_friendPickerController.allowsMultipleSelection = NO;
}
[_friendPickerController clearSelection];
[_friendPickerController loadData];
[self presentViewController:_friendPickerController animated:YES completion:nil];
}
This code is called after login which is done like this in appDelegate following the Facebook Tutorial -
- (void)openSession
{
NSArray *permissions = #[#"friends_about_me"];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
You need to add the following code in viewDidLoad method of your viewController.
if (!FBSession.activeSession.isOpen) {
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession.activeSession openWithCompletionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
switch (state) {
case FBSessionStateClosedLoginFailed:
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
break;
default:
break;
}
}];
}
I have updated XCode to 4.5 and now the Email Function crashes, if I press the button to send an email.
What I am doing wrong?
I have implemented the MessageUI.framework in my header file
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#interface ImpressumViewController : UIViewController <MFMailComposeViewControllerDelegate>
Here is my code for the button:
- (IBAction)kontakt:(id)sender {
MFMailComposeViewController *mailcontroller = [[MFMailComposeViewController alloc] init];
[mailcontroller setMailComposeDelegate:self];
NSString *email =#"Youtube#gmail.com";
NSArray *emailArray = [[NSArray alloc] initWithObjects:email, nil];
[mailcontroller setToRecipients:emailArray];
[mailcontroller setSubject:#"Youtube Tutorials"];
[self presentViewController:mailcontroller animated:YES completion:nil]; }
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
[self dismissViewControllerAnimated:YES completion:nil];
}
You need write following code in this delegate method
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{ switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled: you cancelled the operation and no email message was queued");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved: you saved the email message in the Drafts folder");
break;
case MFMailComposeResultSent:
NSLog(#"Mail send: the email message is queued in the outbox. It is ready to send the next time the user connects to email");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail failed: the email message was nog saved or queued, possibly due to an error");
break;
default:
NSLog(#"Mail not sent");
break;
}
//[self dismissModalViewControllerAnimated:YES];
}
I want to know how to post a status message to Facebook on iOS 6 using the new frameworks on Xcode 4.5. Thanks! :)
Posting a message is rather simple. It's almost like with the Twitter Framework.
First you have to import the Frameworks: Social and Accounts
#import <Social/Social.h>
#import <Accounts/Accounts.h>
In your .h file:
SLComposeViewController *mySLComposerSheet;
This code has to be included inside your action in your .m file:
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) //check if Facebook Account is linked
{
mySLComposerSheet = [[SLComposeViewController alloc] init]; //initiate the Social Controller
mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook]; //Tell him with what social platform to use it, e.g. facebook or twitter
[mySLComposerSheet setInitialText:[NSString stringWithFormat:#"Test",mySLComposerSheet.serviceType]]; //the message you want to post
[mySLComposerSheet addImage:yourimage]; //an image you could post
//for more instance methods, go here: https://developer.apple.com/documentation/social/slcomposeviewcontroller#//apple_ref/doc/uid/TP40012205
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
[mySLComposerSheet setCompletionHandler:^(SLComposeViewControllerResult result) {
NSString *output;
switch (result) {
case SLComposeViewControllerResultCancelled:
output = #"Action Cancelled";
break;
case SLComposeViewControllerResultDone:
output = #"Post Successful";
break;
default:
break;
} //check if everything worked properly. Give out a message on the state.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Facebook" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}];
And what do I have to do, when I just want to receive an alert in case the post was successful, and nothing when the user cancelled the post?
And unfortunately this does not work properly for Twitter... It doesn't dismiss the TweetSheet anymore. Here is my code:
if(NSClassFromString(#"SLComposeViewController") != nil)
{
mySLComposerSheet = [[SLComposeViewController alloc] init]; //initiate the Social Controller
mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]; //Tell him with what social plattform to use it, e.g. facebook or twitter
[mySLComposerSheet setInitialText:[NSString stringWithFormat:story.title,mySLComposerSheet.serviceType]]; //the message you want to post
[mySLComposerSheet addURL:[NSURL URLWithString:story.link]];
//for more instance methodes, go here:https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Reference/SLComposeViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40012205
[mySLComposerSheet setCompletionHandler:^(SLComposeViewControllerResult result) {
NSString *output;
switch (result) {
case SLComposeViewControllerResultCancelled:
output = NSLocalizedStringFromTable(#"As it seems you didn't want to post to Twitter", #"ATLocalizable", #"");
break;
case SLComposeViewControllerResultDone:
output = NSLocalizedStringFromTable(#"You successfully posted to Twitter", #"ATLocalizable", #"");
break;
default:
break;
} //check if everything worked properly. Give out a message on the state.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Twitter" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
- (IBAction)btn_facebook:(id)sender {
SLComposeViewController *facebookcomposer =
[SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[facebookcomposer setInitialText:#"This is just a test"];
[facebookcomposer addURL:[NSURL URLWithString:#"http://www.google.com"]];
[facebookcomposer addImage:[UIImage imageNamed:#"images.jpg"]];
[self presentViewController:facebookcomposer animated:YES completion:nil];
[facebookcomposer setCompletionHandler:^(SLComposeViewControllerResult result)
{
switch (result)
{
case SLComposeViewControllerResultDone:
NSLog(#"done");
break;
case SLComposeViewControllerResultCancelled:
NSLog(#"cancelled");
break;
default:
break;
}
}];
}
- (IBAction)btn_twitter:(id)sender {
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
SLComposeViewController *twitter =
[SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[twitter setInitialText:#"this is just a test"];
[twitter addURL:[NSURL URLWithString:#"http://www.google.com"]];
[twitter addImage:[UIImage imageNamed:#"images.jpg"]];
[self presentViewController:twitter animated:YES completion:nil];
} else {
NSLog(#"it is not configured");
}
}
Ok guys, so I tweaked the original post, works for iOS 6/7. Change ServiceType, Alert Title and Message for Facebook. Enjoy!
- (IBAction)tweetMessage:(id)sender {
if(![SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) //check if Facebook Account is linked
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Unable to Tweet!" message:#"Please login to Twitter in your device settings." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
return;
}
//self.mySLComposerSheet = [[SLComposeViewController alloc] init]; //initiate the Social Controller
self.mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[self.mySLComposerSheet setInitialText:[NSString stringWithFormat:#"I found this Thing, check it out at this Place:\n %# \n", [self someplace]]];
[self.mySLComposerSheet addImage:self.photos.firstObject];
[self presentViewController:self.mySLComposerSheet animated:YES completion:nil];
//}
[self.mySLComposerSheet setCompletionHandler:^(SLComposeViewControllerResult result) {
NSString *output;
switch (result) {
case SLComposeViewControllerResultCancelled:
output = #"Action Cancelled";
break;
case SLComposeViewControllerResultDone:
output = #"Post Successfull";
break;
default:
break;
} //check if everything worked properly. Give out a message on the state.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Twitter" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}];
}
This is how I actually use it in my app though. Smoother and lets the controller do the hard work.
- (IBAction)postToFacebook:(id)sender {
if(![SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
NSLog(#"log output of your choice here");
}
// Facebook may not be available but the SLComposeViewController will handle the error for us.
self.mySLComposerSheet = [[SLComposeViewController alloc] init];
self.mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[self.mySLComposerSheet setInitialText:[NSString stringWithFormat:#"I found this Thing, check it out at SomeWhere:\n %# \n", [self someURLString]]];
[self.mySLComposerSheet addImage:self.photos.firstObject]; //an image you could post
[self presentViewController:self.mySLComposerSheet animated:YES completion:nil];
[self.mySLComposerSheet setCompletionHandler:^(SLComposeViewControllerResult result) {
NSString *output;
switch (result) {
case SLComposeViewControllerResultCancelled:
output = #"Action Cancelled";
break;
case SLComposeViewControllerResultDone:
output = #"Post Successfull";
break;
default:
break;
}
if (![output isEqualToString:#"Action Cancelled"]) {
// Only alert if the post was a success. Or not! Up to you.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Facebook" message:output delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
}];
}