MFMailComposeViewController Opens then closes - ios

I've got a MFMailComposeViewController and I believe it is implemented correctly. However when it is displayed on the screen (through modal) it just opens, hangs for a second, then closes and logs MFMailComposeResultCancelled
any thoughts?
if ([MFMailComposeViewController canSendMail]){
MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
if( composer == nil ){
UIAlertView* alert_view = [[UIAlertView alloc] initWithTitle:#"message"
message:#"You will need to setup a mail account on your device before you can send mail!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert_view show];
return;
}else{
composer.mailComposeDelegate = self;
[composer setSubject:#"I have an issue"];
[composer setMessageBody:#"" isHTML:NO];
[composer setToRecipients:#[#"email"]];
}
[self presentViewController:composer animated:YES completion:^{
;
}];
EDIT found these in the log
Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0xcda5e90>.
The operation couldn’t be completed. (Cocoa error 4097.)

MFMailComposeResultCancelled is called if you have any changes that occur to the UI when the MFMailComposer is pulled up.
I must be the default iOS Navigation header, though you can change the tint.

On your completion if you don't do anything, put nil, probably this is the problem.

Related

UIAlertView delayed or not showing up when calling methods from another view

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.

PresentViewController only working once

I'm a bit dazzled here. And I do think it might be something stupid, but here it goes.
I'm using ABPadLockScreen to set a password and it works just fine when I open the app first time and if the app is closed (terminated) and reopened, but if I just go home and return to it I get the following warning
Warning: Attempt to present <ABPadLockScreenViewController: 0x7fdc70f1d5a0> on <ViewController: 0x7fdc70f18e00> whose view is not in the window hierarchy!
Just for more information here is the code that triggers it, it's inside the viewDidAppear
AppDelegate *delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if (!self.pin && delegate.terminated) {
// [[[UIAlertView alloc] initWithTitle:#"No Pin" message:#"Please Set a pin before trying to unlock" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
//return;
[self dismissViewControllerAnimated:YES completion:nil];
} else if (!self.isPin && !delegate.terminated) {
ABPadLockScreenViewController *lockScreen = [[ABPadLockScreenViewController alloc] initWithDelegate:self complexPin:YES];
[lockScreen setAllowedAttempts:3];
lockScreen.modalPresentationStyle = UIModalPresentationFullScreen;
lockScreen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:lockScreen animated:YES completion:nil];
}
If you're wondering about the delegate, it was so the Password Screen would show up when the app was simply closed and reopened and that's when the warning occurs.
Also, if I simply switch from one view to another, the damn thing shows up again.
Thanks in advance

Why calling MFMailComposeViewController deallocates the view that called it?

I have this simple function to write mail on ios 8.0, xcode 6.1. Nothing special, it ever worked till ios 8.0 said hello.
The function sendMail sends a mail when a button gets tapped (set via storyboard). I debugged it and the code seems ok, but it crashes with a EXC_BAD_ACCESS code=1 error whenever you're supposed to return back to the main app, like when you tap the send or dismiss button of the MFMailComposeViewController. It seems to me that my View, i mean the view calling the MFMailComposeViewController is deallocated when the MFMailComposeViewController is called, so that when it get dismissed, there's nothing to return on. Some ideas to solve the problem?
[The function didFinishWithResult is never reached: the crash happens before.]
EDIT: To be precise it crashes with bad_access if in the presentViewController i set animated to NO. If it is YES it complain about 'unbalanced calls to begin/end appearance transitions' and tapping send/dismiss does nothing (it not returns. The mail view is alive but tap button does nothing)
EDIT: I am right about the deallocation. He have the same problem but it does not seems to have a valid solution MFMailComposeViewController crash in iOS6 ARC
In my case Arc is turned off and i cannot turn it on for various reasons. The theory is confirmed by zombie instrument. It says 'An Objective-C message was sent to a deallocated 'View' object (zombie) at address: 0x14e01720'
View.h
included MFMailComposeViewControllerDelegate and imported
#import <MessageUI/MFMailComposeViewController.h>
View.m
-(IBAction)sendEmail:(id)sender{
NSString *mailDiretta=emailText.currentTitle;
composer = [[MFMailComposeViewController alloc] init];
[composer setMailComposeDelegate:self];
if ([MFMailComposeViewController canSendMail]) {
[composer setToRecipients:[NSArray arrayWithObjects:mailDiretta, nil]];
[composer setSubject:#"Infos"];
[composer setMessageBody:#"Write to me, dude!" isHTML:NO];
[composer setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentViewController:composer animated:YES completion:NULL];
[composer release];
} else
[composer release];
}
// function below is never reached
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"error"
message:[NSString stringWithFormat:#"error %#", [error description]]
delegate:nil cancelButtonTitle:#"dismiss" otherButtonTitles:nil, nil];
[alert show];
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
I would assume it's because you're releasing the composer before it finishes.
[composer release];
EDIT: How is this property initialized and why is it a property? Create it in the method and try. Also, your unbalanced calls are happening because you're animating a UIAlert at the same time you are animating the mail controller dismiss. Each needs to finish prior to prevent that message.
composer = [[MFMailComposeViewController alloc] init];
Try to remove the property and initialize in the function.
MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
Make sure you added the delegate properly as well.
#import <MessageUI/MessageUI.h>
#interface YourViewController : UIViewController <MFMailComposeViewControllerDelegate>
Set your delegate like this
composer.mailComposeDelegate = self;
For the unbalanced calls, rearrange your alert like this...
[self dismissViewControllerAnimated:YES completion:NULL];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"error"
message:[NSString stringWithFormat:#"error %#", [error description]]
delegate:nil cancelButtonTitle:#"dismiss" otherButtonTitles:nil, nil];
[alert show];
EDIT 2:
After seeing your comment about not being able to use ARC due to one class I would advice you to simply set a -fno-objc-arc compiler flag on that class and enable ARC across your project and make your life WAY easier.
Disable Automatic Reference Counting for Some Files

E-mail account information with QLPreviewController

I am using QLPreviewController for showing the pdf. And I am sending pdf by tapping the share button and then tap on email in the QLPreviewController.
But i don't know how to get that share button method in QLPreviewController to validate that the email account is available or not. Here is the screenshot:
Please let me know about this.
Thanks in advance.
if you have UInavigationController then you can add a bar button for sharing the content. Or you can add a share button in your viewcontroler.
Use MessageUI. Add the delegates MFMessageComposeViewControllerDelegate, MFMailComposeViewControllerDelegate.
- (IBAction)contactBtn:(id)sender {
if ([MFMailComposeViewController canSendMail]){
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
[controller setSubject:#"Subject"];
[controller setMessageBody:#" " isHTML:NO];
[controller setToRecipients:[NSArray arrayWithObjects:#"a#wa.com",nil]];
controller.mailComposeDelegate = self;
[self presentViewController:controller animated:YES completion:NULL];
}
else{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Failed!" message:#"Mail can not be sent. Check your email settings." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil] ;
[alert show];
}
}
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[self dismissViewControllerAnimated:YES completion:NULL];
}
The QL previewer is working on separate process. Something like a different app. So there is no way to customize the share button. see details here
This may help you. See this answer.

MFMessageComposeViewController addAttachmentData on iPad iOS7 black screen

I have a MFMessageComposeController, and I want to send images via iMessage (SMS not available on my iPad).
This is my code:
- (void)presentMessageController {
if(![MFMessageComposeViewController canSendAttachments])
{
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device doesn't support sharing photos via SMS!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[warningAlert show];
return;
}
MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
messageController.messageComposeDelegate = self;
[messageController addAttachmentData:imgData typeIdentifier:(NSString *)kUTTypePNG filename:#"image.png"];
// Present message view controller on screen
[self presentViewController:messageController animated:YES completion:nil];
}
The problem seems to be in [messageController addAttachmentData...]. The messageController is not presented, instead a blank screen appears, and app is hanging up, and after 1-2seconds, the delegate responds with MessageComposeResultCancelled, and I see this in console:
timed out waiting for fence barrier from com.apple.mobilesms.compose
Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!
If I comment that line, the messageController is presented (iMessage is opened).
IMPORTANT:
This is happening when testing on iPad (I tested on iPad 2 only, with iOS 7.0.3 installed). Same code works perfect in iPhone 5, 4, 4S with iOS 7.0.3.
When black screen appears, there is no way to return to app. You have to terminate the app, and restart.
Anybody experiencing same issue? Please help. Thanks.
try changing:
[messageController addAttachmentData:imgData typeIdentifier:(NSString *)kUTTypePNG filename:#"image.png"];
to:
[messageController addAttachmentData:imgData typeIdentifier:#"public.data" fileName:#"image.png"];
Call presentMessageController method after some delay
[self performSelector:#selector(presentMessageController) withObject:nil afterDelay:0.5];

Resources