MFMailComposer hangs app - no crash report - happens after users upgrade iOS - iphone

EDIT: I eventually contacted Apple DTS. After I provided a stackshot from an affected user, DTS decided I should file a bug with Apple BugReporter. So, at this point, I think it's an issue with MFMailComposer, but it's unresolved. The Apple bug number is 13602051
I have a bug that has been coming up again and again in an app.
Some users who upgrade their iOS version report that they can no longer use the email export in my app, which uses MFMailComposer. The app freezes, and doesn't generate a crash report.
My code is pretty simple, and I can't reproduce the reported bug, but many users have now said this happens after an iOS update. Here is the code:
// using ARC, so no reference counting
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
#autoreleasepool {
if (gpxFilePath) {
NSData *gpx = [NSData dataWithContentsOfFile:gpxFilePath];
[controller addAttachmentData:gpx mimeType:#"text/gpx" fileName:[self cleanFileName]];
gpx = nil;
}
}
[controller setSubject:subject];
[controller setMessageBody:body isHTML:YES];
[[MAP_APP_DELEGATE mainController] presentModalViewController:controller animated:YES];
After this is called, the email view comes up, but then is unresponsive.

I'm using the next code for iOS 6.1 and it works for me.
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc]init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"subject"];
User *user = [user_array objectAtIndex:1];
NSArray *toRecipients = [NSArray arrayWithObjects:#"mail address", nil];
[mailer setToRecipients:toRecipients];
NSArray *cc = [NSArray arrayWithObjects:#"mail address", nil];
[mailer setCcRecipients:cc];
NSDictionary *dic = [one array objectAtIndex:0];
NSString *description = [dic objectForKey:#"Description"];
NSString *emailBody = description;
[mailer setMessageBody:emailBody isHTML:NO];
[self presentViewController:mailer animated:YES completion:nil];
[mailer release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failure"
message:#"Your device doesn't support the composer sheet"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
Remember that simulator is not able to send e-mail, so alert view will be shown in this case.
Note 1: presentModalViewController is deprecated in iOS 6.0
Note 2: try to send the email without data to check if this is what causes the issue

This should solve your problem.
[[MAP_APP_DELEGATE mainController] presentModalViewController:controller animated:YES];
controller = nil;

Related

App crashing on changing views after login

Good morning!
I am very new to iPhone/iPad programming
My app is crashing (signal SIGABRT) after trying to change views after a Login
-(void)checkLogin {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"LoginData" ofType:#"txt"];
NSString *myText = [NSString stringWithContentsOfFile:filePath];
//Parse lines into an NSArray;
NSArray *results= [myText componentsSeparatedByString:#"\n"];// Assumes Mac line end return
if([txtUsername.text isEqualToString: [results objectAtIndex:0]]&& [txtPassword.text isEqualToString: [results objectAtIndex:1]])
{
Clients * clients = [[Clients alloc] initWithNibName:#"clients" bundle:nil];
[self presentModalViewController:clients animated:YES];
}
else
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Login"
message:#"Wrong credentials"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[alert show];
}
}
#end
The app is crashing at this line
[self presentModalViewController:clients animated:YES];
Thank you very much!
Clients * clients = [[AboutUs alloc] initWithNibName:#"clients" bundle:nil];
[self presentModalViewController:clients animated:YES];
I think the first line is where your app gets stuck. turn it into:
Clients *clients = [[Clients alloc] initWithNibName:#"clients" bundle:nil];
[self presentModalViewController:clients animated:YES];
This code should work, but In your question, you put a certain aboutUs in your code.
I don't know what you want to do with this from you question, but if you want to put this AboutUs controller inside your Clients controller, you should use something like:
Clients *clients = [[Clients alloc] initWithRootViewController:aboutUs];
hope this helps you
Have you tried doing it like this:
Clients *myClients = [[Clients alloc] init];
[self presentViewController:clients animated:YES completion:^(void) {
}];
It should work properly. If it still crashes, something in the Clients class is going wrong.

Data Attachement in E-mail?

I save my objects in NSMutablearray in NSData formate.No i am try to attached in E-mail Body.here is code.
- (IBAction)sendEmail
{
if ([MFMailComposeViewController canSendMail])
{
NSArray *recipients = [NSArray arrayWithObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController
alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
NSString *string = [viewArray componentsJoinedByString:#"\n"];
NSString *emailBody = string;
NSLog(#"test=%#",emailBody);
[controller setMessageBody:emailBody isHTML:YES];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email." delegate:self
cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
I get no error,but not see any data in E-mail.in NSLog i see this..2012-05-07 15:33:22.984 Note List[273:207] test=>]please suggest any one better solution for me how i attached my NSMutableArray data in E-mail body..
i'm not clear with your question, try this way to set your data. and check the values you are going to set before passing it to composer,
see this
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSString *mSubject;
if(isInvite)
{
mSubject=#"TAPP Invitation";
}
else
{
mSubject= #"TAPP email";
}
[picker setSubject:mSubject];
NSString *mBody;
if(isInvite)
{
NSString *pTappId=[[DataModel sharedDataModel] getValueForKey:USER_TAPP_ID];
NSString *currentUserName=[[DataModel sharedDataModel] getValueForKey:CURRENT_USER_NAME];
mBody=[NSString stringWithFormat:#"<HTML><BODY>Hi,<br><br>We already know one another, and I would like us to keep in touch.<br><br>Let's connect through TAPP (Download Here) a smarter, private way to exchange and manage contact information.<br><br>Join TAPP and secure your preferred, unique ID before it is too late, and then connect with me. My TAPP ID is %#.<br><br>For more information, click here<br><br>Regards,<br><br>%#</BODY></HTML>",pTappId,currentUserName];
}
else
{
mBody= [NSString stringWithFormat:#"<HTML><BODY><br /><br />Connected by <a href=http://www.mytapp.com>TAPP</a></BODY></HTML>"];
}
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:selectedEmailId];
//NSArray *toRecipients = [NSArray arrayWithObject:#""];
[picker setToRecipients:toRecipients];
// Attach an image to the email
//NSString *path = [[NSBundle mainBundle] pathForResource:#"rainy" ofType:#"png"];
//NSData *myData = UIImagePNGRepresentation(photo.image);
//[picker addAttachmentData:myData mimeType:#"image/png" fileName:#"abc.png"];
// Fill out the email body text
NSString *emailBody = mBody;
[picker setMessageBody:emailBody isHTML:YES];
[self presentModalViewController:picker animated:YES];
[picker release];
If you're trying to attach the data as a standard email attachment, use this:
NSData *data = UIImageJPEGRepresentation(artworkImageView.image, 0.0);
[picker addAttachmentData:data mimeType:#"image/jpeg" fileName:#"Photo.jpeg"];
The data can be whatever you want, just give an appropriate mime type and file name.
Maybe your definition of the viewArray is wrong?
In your .h file:
#property(nonatomic, retain) NSMutableArray *viewArray;
In your .m file:
#synthesize viewArray;
Please have a look at the apple docs for the method "componentsJoindedByString", because I can't found a error quite know.
My test with a viewArray initialization from the api: (works good)
- (IBAction)sendEmail {
self.viewArray = [NSArray arrayWithObjects:#"here", #"be", #"dragons", nil];
if ([MFMailComposeViewController canSendMail])
{
NSArray *recipients = [NSArray arrayWithObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController
alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
//is anything in the array?
NSLog(#"viewArray: %#", viewArray);
NSString *string = [viewArray componentsJoinedByString:#"\n"];
NSString *emailBody = string;
NSLog(#"test=%#",emailBody);
[controller setMessageBody:emailBody isHTML:YES];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email." delegate:self
cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}

How can I convert NSMutableArray into NSString?

I am trying to convert (or copy?) a NSMutableArray into a NSString. I guess my problem is
that I don't really understand the structure of a NSString. After conversion I want to
attached it in email body. Here is my code:
- (IBAction)sendEmail
{
NSLog(#"sendEmail");
[textView resignFirstResponder];
[textView1 resignFirstResponder];
if ([MFMailComposeViewController canSendMail])
{
// set the sendTo address
NSMutableArray *recipients = [[NSMutableArray alloc] initWithCapacity:1];
[recipients addObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
NSString *string = [string appendString:[NSString stringWithFormat:"%#", [viewArray objectAtIndex:i]]];
[controller setMessageBody:string isHTML:NO];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
EDIT:
after reading your comment, it is pretty much clear that what you are trying to do is archiving/unarchiving an array containing objects of various kinds. So, you should try using:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
to get an NSData object that you can then send as an attachment with an email message (or in whatever other persistency layer you need).
Keep in mind that this approach will work only if the objects stored in the array support the NSCoding protocol (you can check that in the reference for each type you are using: it clearly lists all the supported protocols). Considered that you say that your object are already stored as NSData, there should be no problem. Just archive the array, so you will be able to unarchive it later, if required.
If you have some custom type that does not support NSCoding, you will need to implement it as described in Encoding and Decoding Objects.
OLD ANSWER:
I am not sure I understand your problem, but what about using componentsJoinedByString:
E.g.:
NSString *string = [viewArray componentsJoinedByString:#"\n"];
Doing like this, the content of your array (provided it is made of strings) will be presented as a list of strings. If you use description, your array will be converted into a string without giving you much control on its format (it will add curly braces and other syntactic sugar).
I suspect what you wanted to do was create a loop on all the elements in viewArray and append them to an NSString string. However, as #sergio has suggested, I think componentsJoinedByString would be a better option.
This is what your method would look like with that change, I have also cleaned up some other parts of the method. It looks like there was a memory leak, recipients, in your original version.
- (IBAction)sendEmail
{
NSLog(#"sendEmail");
[textView resignFirstResponder];
[textView1 resignFirstResponder];
if ([MFMailComposeViewController canSendMail])
{
// set the sendTo address
NSArray *recipients = [NSArray arrayWithObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
NSString *string = [viewArray componentsJoinedByString:#"\n"];
[controller setMessageBody:string isHTML:NO];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
}
This will combine the elements of the viewArray and place a newline \n between each element. You could replace the #"\n" with #"" or #" " depending on exactly what you want to do. If the elements of the array are not NSStrings then the elements description method will be called and the output of that used in the resulting string.
Depends on the format you'd like your string to have. You could always use the array's description like this:
NSString *myString = [myArray description];

MFMailComposeViewController canSendMail change alert if returned no

I use MFMailComposeViewController canSendMail in my app everything works great but if there are no accounts on the iPhone or iPad it returns a standard alertview what I would like to change. If I put a alert in the else it will return 2 alerts. Is there a way to change the standard alert it returns? Or at least change the text in it?
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
if ([MFMailComposeViewController canSendMail]) {
controller.mailComposeDelegate = self;
controller.navigationBar.tintColor = [UIColor grayColor];
NSArray *toRecipients = [NSArray arrayWithObject:#"info#info.nl"];
[controller setToRecipients:toRecipients];
[controller setSubject:#"bericht van info"];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else {
}
try one thing.. Move your MFMailComposeViewController initialization code inside the canSendMail block.
Move the alloc of the 'MFMailComposeViewController' inside the if:
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
controller.navigationBar.tintColor = [UIColor grayColor];
NSArray *toRecipients = [NSArray arrayWithObject:#"info#info.nl"];
[controller setToRecipients:toRecipients];
[controller setSubject:#"bericht van info"];
[self presentModalViewController:controller animated:YES];
[controller release];
} else {
// Display custom alert here.
}
You can check if the device can send emails with
[MFMailComposeViewController canSendMail]
And, if not, show the dialog in your side

MFMailComposer - works in simulator but not in iPhone 2G

I am trying to add MFMailComposer to my iPhone app and not having much luck getting it to launch in my iPhone 2G. It always launches the email app to the accounts page and closes my app. Works like a charm in the simulator.
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self displayComposerSheet];
}
-(void)displayComposerSheet
{
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil)
{
// you have the MFMailComposeViewController class
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSArray *mailArr = [[NSArray alloc] initWithObjects:self.sendTo,nil];
[picker setSubject:#"Hello from iCamp America"];
[picker setToRecipients:mailArr];
NSString *emailBody = #"\n\n\email created with iCamp America\nwww.iCampAmerica.com";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
[picker release];
[mailArr release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"You cannot send an email !" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
The MFMailComposeViewController is only available on iPhone OS > 3.0. Are you running that version your development phone?
Silly me - I found that I had conflicting calls to send the email - I was calling BOTH the mailTo:URL and the MFMailComposer methods with the same action trigger.....