MFMailComposeViewController dismisses right away - objective-c

The situation is the MFMailComposeViewController was going to be presented. I saw it was presented half-way done, but then it got dismissed.
This is the error:
_serviceViewControllerReady:error: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "The operation couldn’t be completed. (_UIViewServiceInterfaceErrorDomain error 3.)"
This is my source code to present the MFMailComposeViewController:
-(void) MailExecute {
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
[mailViewController setSubject:NSLocalizedString(#"Check this new look", #"")];
[mailViewController setMessageBody: #"my new look" isHTML:YES];
[self presentModalViewController:mailViewController animated:YES];
[mailViewController release];
}
else
{
UIAlertView *alertInternal = [[UIAlertView alloc]
initWithTitle: NSLocalizedString(#"Notification", #"")
message: NSLocalizedString(#"You have not configured your e-mail client.", #"")
delegate: nil
cancelButtonTitle:NSLocalizedString(#"OK", #"")
otherButtonTitles:nil];
[alertInternal show];
[alertInternal release];
}
}
The weird point is that sometimes it happens, sometimes it doesn't.
Please help me on this! I spend almost 1 working day to resolve this but no succeed.

This problem can occur when displaying a remote view controller -- a view controller run in another process -- as indicated by the UIViewService reference in the error message.
I've had this problem when displaying an SKStoreProductViewController, which is also a remote view controller. I'm not sure what the root cause is; the only thing that seemed to trigger it for me was presenting the view controller repeatedly.
For the SKStoreProductViewController I was able to check for this error in the completion block of the loadProductWithParameters:completionBlock: method. Does the MFMailComposeViewControllerDelegate give you a callback with an error about this? It may be that all you can do is listen for this error and show an error message to the user.
We should both probably file an apple radar about this.

Your code looks correct, and as stated the error message strongly suggests this has something to do with UIView proper (not MFMail specifically). The problem almost surely lies somewhere elsewhere within your code, and might be challenging to troubleshoot.
Some things to look for:
Other animations or view controller transitions/dismissals happening simultaneously or incorrectly (possibly like this)
Release/retain issues, of course
If none of that seems like the fix, try commenting-out everything else happening in the view controller that calls this method and see if it works then.
If you still can't get it working, present the simplest version you can of failing code so we can troubleshoot further. :)

Do you have anything in your viewDidDisappear: or viewWillDisappear methods that would dismiss a view controller?
If not, can you post more of your code for the ViewController that presents the MFMailComposeViewController?

I know this is the late reply, but may be help some other.
Just now face the same problem, By resetting the simulator work fine for me for this same issue. Let me know if this helps.

After I stored the MFMailComposeViewController in a strong property of my class instead of a local variable I could not reproduce the self-dismissing behaviour any more.

The issue for me was an incorrect argument when calling the attachment function. If you are having this issue with an email attachment I suggest following the solution found in this thread, as follows:
NSString *path = [self getDatabaseFilePath];
NSData *myData = [NSData dataWithContentsOfFile:path];
[picker addAttachmentData:myData mimeType:#"application/x-sqlite3" fileName:[path lastPathComponent]];

MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc]init];
if ([MFMailComposeViewController canSendMail])
{
mailComposer.mailComposeDelegate = self;
[mailComposer setToRecipients:[NSArray arrayWithObject:#"support#kapsie.com"] ];
[mailComposer setSubject:#"Kapsie App Contact Support"];
[mailComposer setMessageBody:#"Type Your Feedback message here" isHTML:NO];
[self presentViewController:mailComposer animated:YES completion:nil];
}
Use above code and check it on device.

Use of modelViewController is deprecated in iOS 6 ,
use
[self presentViewController:mailView animated:YES completion:nil];

I face the same problem and the solution was:
I delete the overall application appearence related code like
[[UILabel appearance]setText:#""]
and replace with the code
[[UILabel appearanceWhenContainedIn:[self class], nil] setText:#""];
Now it is working fine so be carefull on overall application appearence changes: it might be navigationbar appearance, so and so

Related

performSelectorInBackground causes random crash when view is dismissing

I'm having some random crashes at this part of my code:
-(void) goBack {
[self performSelectorInBackground:#selector(addActivityIndicator) withObject:nil];
[self.navigationController popViewControllerAnimated:YES];
}
- (void)addActivityIndicator {
#autoreleasepool {
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithCustomView:activityView];
[activityView startAnimating];
self.navigationItem.leftBarButtonItem = barButton;
}
}
When I want to exit the screen where these method exists, the other ViewController have to process some data. To inform the user that processing is occurring I add an activity indicator to the left button in my navigation bar.
The problem is that sometimes I get an exc_bad_access in addActivityIndicator method. The frequency is very random, sometimes the XCode shows the error at the end of #autoreleasepool, sometimes at the line self.navigationItem.leftBarButtonItem = barButton;
I imagine that sometimes my viewController is destroyed but the thread is still running and try to access the navigationItem of a object that don't exists anymore. But I'm not sure if that is the problem and I don't know how to fix it.
I'm using ARC in my project and this problem occurs in all iOS versions that I tested.
Please, anyone can explain me what is happening and how can I fix this?
Thanks.
You should never do UIKit stuff in the background.
By calling [self performSelectorInBackground:#selector(addActivityIndicator) withObject:nil]; you are updating the UI on a background thread. You should only ever update the UI on the main thread.
Edit
Based on your comment you are trying to have the UI update before the view pops. The way to do that would be:
[self addActivityIndicator]
[navigationController performSelector:#selector(popViewControllerAnimated:) withObject:[NSNumber numberWithBool:YES] afterDelay:0];
You could also look into dispatch_after

Strange error when dismissing MFMailComposeViewController: error: address doesn't contain a section that points to a section in a object file

I am getting a really weird error MFMailCompseViewController. The error is "error: address doesn't contain a section that points to a section in a object file". The app crashes after MFMailCompseViewController dismisses and the email actually get sent.
This is specific to MFMailComposeViewController as I have tried to present a plain view controller modally and it dismisses fine.
Here is the code I wrote to calland present mail composer:
- (void) emailImage:(UIImage *)img {
//verified that the image is being returned correctly
UIImage *img1 = [[_delegate photoBrowser:self photoAtIndex:0] underlyingImage];
MFMailComposeViewController *mfViewController = [[MFMailComposeViewController alloc] init];
mfViewController.mailComposeDelegate = self;
NSString *subject = #"Check out this photo I took - Cap That App";
[mfViewController setSubject:subject];
NSData *imgData = UIImageJPEGRepresentation(img1, 1.0);
[mfViewController addAttachmentData:imgData mimeType:#"image/jpg" fileName:#"photo.jpg"];
NSString *contactMessage = #"\n\nSent via Cap That - Available in the Apple App Store";
[mfViewController setMessageBody:contactMessage isHTML:YES];
[self presentViewController:mfViewController animated:YES completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Status:" message:#"" delegate:nil cancelButtonTitle:#"ok" otherButtonTitles:nil] autorelease];
switch (result) {
case MFMailComposeResultCancelled:
alert.message = #"You chose not to send the email.";
break;
case MFMailComposeResultSaved:
alert.message = #"Your email was saved as a draft. It has not been sent yet.";
break;
case MFMailComposeResultSent:
alert.message = #"Your email has been sent!";
break;
case MFMailComposeResultFailed:
alert.message = #"There was an error sending the email. Please verify your email is working and try again.";
break;
default:
alert.message = #"You chose not to send the email.";
break;
}
[self dismissViewControllerAnimated:YES completion:^(void) {
[alert show];
}];
}
Thanks in advance for anyone's help on this.
I'm getting the same error in my app, acting on a tap gesture on a HUD. My gesture recognizer method is using a block property on the HUD to perform the needful actions, and there's where it's crashing (the code within the block never gets to run). Apparently the program cannot access that code, and since you also have a completion block that might be a clue to what's happening.
I don't see that I'm doing anything wrong in my code, and you don't seem to be doing that either, so maybe it's a bug. Are you by any chance running a developer preview of Xcode (4.4 or 4.5)?
Edit: it turns out my problem was that the code block property was being released before it got the chance to run. I think a similar thing might happend in your case, with the alert var. Can you try moving the alert init within the completion block?
Edit 2: As an alternative, try prefixing the alert init with __weak (or __unsafe_unretained if you're targetting iOS 4.3), that should do it. If you're not using ARC, use __block instead.

MFMessageComposeViewController first alloc takes seconds

I am trying to show an MFMessageComposeViewController with the following code:
controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText])
{
controller.body = [NSString stringWithFormat:#"%#%#%#", itemString, amountString, callTimeString];
controller.recipients = [NSArray arrayWithObject:#"12345678"];
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
The problem is when I press the button to bring up the MFMessageComposeViewController, the alloc takes a few seconds. I have tried moving the alloc line to my viewDidLoad method, however this just moves the problem and I end up waiting a few seconds for the view to load.
Is there any method to speed up the alloc and showing of my MFMessageComposeViewController or use a delegate method or something?
Thanks.
Well, what you are doing seems about right. You are not doing anything wrong. Check this - Can't set recipients of MFMessageComposeViewController? & the link attached in the answer
I had a similar problem, check out my answer here: I need a callback when MFMessegeComposeViewController finally loads
For me it wasn't the alloc taking too long, it was the presentModalViewController of the MFMessageComposeViewController, which blocks on Apple's code on the UI thread, so no way to background it except for throwing up your own progress view.

iPad Popover -[UIPopoverController initWithContentViewController: must not be called with `nil`

I'm still working my way around the iOS SDK and I have another probably easy one for you.
I'm getting the following error when attempting to present a popover:
CoreAnimation: ignoring exception: -[UIPopoverController initWithContentViewController: must not be called with nil.
I thought I had put in code to deal with this, although apparently not. Anyway, code is below. Any thoughts on this would be great. Cheers!
if(popoverController == nil)
{
NSLog(#"is nil");
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverDownload];
}
popoverController.delegate = self;
[popoverController presentPopoverFromRect:CGRectMake(0,0,400,200) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
UPDATE
I guess I'm not initialising popoverDownload correctly/at all.
In my .h file
PopoverDownloadViewController *popoverDownload;
#property (nonatomic,retain) PopoverDownloadViewController *popoverDownload;
UPDATE WITH ANSWER
And it was as easy as...
PopoverDownloadViewController *popoverDownload = [[PopoverDownloadViewController alloc] init];
Just to mark this answer closed. I needed to initialise the popover using the following code...
PopoverDownloadViewController *popoverDownload = [[PopoverDownloadViewController alloc] init];
Thanks to omz for the hints in the right direction.

How to move the buttons in a UIAlertView to make room for an inserted UITextField?

[EDIT] Hmm. Perhaps this question should be titled "what is the default user-input dialog view called in CocoaTouch?" I realize that I can create an entire view that is exactly what I want, and wrap it in a view controller and presentModalView -- but I was sort of hoping that there was a standard, normal user-input "dialog" view that came-with Cocoa-touch. "Enter your name", "enter text to search", etc., are VERY common things!
Anyway... here's the question as I originally asked it:
This code:
UIAlertView* find = [[UIAlertView alloc] init];
[find setDelegate:self];
[find setTitle:#"Find"];
[find addButtonWithTitle:#"Cancel"];
[find addButtonWithTitle:#"Find & Bring"];
[find addButtonWithTitle:#"Find & Go"];
[find addButtonWithTitle:#"Go To Next"];
[find addSubview:_findText];
CGRect frm = find.frame;
int height = frm.size.height + _findText.frame.size.height + 100; // note how even 100 has no effect.
[find setFrame:CGRectMake(frm.origin.x, frm.origin.y, frm.size.width, height)];
[find setNeedsLayout];
[find show];
[find release];
Produces this Alert view:
Find Alert http://www.publicplayground.com/IMGs/Misc/FindAlert.png
(I started with the code from this question by emi1Faber, and it works as advertised; however, as I state in my comment, the cancel button overlays the text field.)
How do I reshuffle everything to make the text field fit properly? [findAlert setNeedsLayout] doesn't seem to do anything, even after I [findAlert setFrame:tallerFrame]. Hints?
Thanks!
The simplest (and most proper way) to move the text view down is to add a message
[find setMessage:#"\n"];
Also, the reason your frame isn't taking effect is that -show sets the frame and creates the view hierarchy before starting the animation. You should also make the text view the first responder so the keyboard pops up.
Full example:
// Create Alert
UIAlertView* av = [UIAlertView new];
av.title = #"Find";
// Add Buttons
[av addButtonWithTitle:#"Cancel"];
[av addButtonWithTitle:#"Find & Bring"];
[av addButtonWithTitle:#"Find & Go"];
[av addButtonWithTitle:#"Go to Next"];
// Make Space for Text View
av.message = #"\n";
// Have Alert View create its view heirarchy, set its frame and begin bounce animation
[av show];
// Adjust the frame
CGRect frame = av.frame;
frame.origin.y -= 100.0f;
av.frame = frame;
// Add Text Field
UITextField* text = [[UITextField alloc] initWithFrame:CGRectMake(20.0, 45.0, 245.0, 25.0)];
text.borderStyle = UITextBorderStyleRoundedRect;
[av addSubview:text];
[text becomeFirstResponder];
Note: You can also modify the subviews of UIAlertView, but since Apple has already changed the UIAlertView layout once you should check their class descriptions and frames against known values before setting new ones. You can even get something like this:
(source: booleanmagic.com)
Even if you can get this working it's not going to be very iPhone-y. The UIAlertView really is not designed for user input like this. If you look in all the Apple apps you'll see that they use a new view that displayed using the presentModalViewController: method of UIViewController.
Edit: This advice is no longer as true as it was when I wrote it. Apple have increasingly used alert views as text entry boxes and iOS5 even includes native support without having to mess around with views (check out the alertViewStyle property).
I think maybe if you need to have four buttons then using a custom UIViewController is probably still the right way to go. But if you just want to enter a password with OK/Cancel buttons then it's fine.
Zoul proposed the best method, to capture user input just do:
a) Add the UITextFieldDelegate protocol to your class.
b) Do something like
UIAlertView *insertScore = [UIAlertView new];
[insertScore setDelegate:self];
[insertScore setTitle:#"New Title!"];
[insertScore addButtonWithTitle:#"Cancel"];
[insertScore addButtonWithTitle:#"Ok"];
insertScore.message = #"\n";
[insertScore addTextFieldWithValue:#"Input" label:#"player"];
[[insertScore textField] setDelegate:self];
[insertScore show];
[insertScore release];
c) The crucial part was to set the delegate of the textField to self, then to access data you can simply:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"%#",[[alertView textField] text]);
}
Hope this helps someone, since I had to think a bit to get it right.
Most probably You would want to look into the addTextFieldWithValue method of the UIAlertView? Add the following code somewhere at the top of Your class:
#interface UIAlertView ()
- (void) addTextFieldWithValue: (NSString*) val label: (NSString*) label;
- (UITextField*) textField;
#end
It’s not official, but IMHO it’s not getting You rejected from the App store and it’s much better solution than hacking the textfield into the dialog Yourself.
Explains how to set the number of columns, have not tested it.
http://iloveco.de/uikit-alert-types/
However there is a private method,
setNumberOfRows:(int)n that will allow
you to set a maximum number of rows to
display the buttons in. To use this
method we need to add our own
additions to the UIAlertView class. We
do this by adding an #interface for
UIAlertView in our .m file.
// extend the UIAlertView class to remove the warning caused
// by calling setNumberOfRows.
#interface UIAlertView (extended)
- (void) setNumberOfRows:(int)num;
#end
This will allow us to call the method without the compiler throwing us a warning.
[myAlert setNumberOfRows:2];
Try putting in some (\n)s after the title in the UIAlertView initialization. That will push down the buttons. And I agree with Stephen here. There are chances that Apple might reject an app if it uses controls in a way they shouldn't be. (there's some clause in the Human Interface Guidelines about that!)
This simpler method works for me:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"UIAlertView"
message:#"<Alert message>" delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert addTextFieldWithValue:#"" label:#"Text Field"];
Hope that helps. Oh if you needed multiple button rows then it's:
[alert setNumberOfRows:3];
Cheers
https://github.com/TomSwift/TSAlertView
This library actually creates the control from scratch rather than attempting to hack UIAlertView, which is generally a Bad Plan (TM)