MFMailComposeViewController in the delegate - iphone

The question deals with an application which uses many views in a UINavigation controller Style.
I have a simple function in my delegate which can be used by all views to plot-out error message
// In Appdelegate.m
-(void)popErrorWindow:(NSString *)theError
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:theError
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Report",nil];
[alert show];
[alert release];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1)
{
NSLog(#"report");
[self mailIt:#"error name"];
}
}
Now, wanting to have a mechanism that will email the error along with some other data I have created this:
-(void)mailIt:(NSString *)theError {
NSLog(#"Mail it");
pickerMail = [[MFMailComposeViewController alloc] init];
pickerMail.mailComposeDelegate = self;
[pickerMail setSubject:#"error via email"];
NSMutableString *body = [NSMutableString string];
[body appendString:#"Error XXX "];
[pickerMail setMessageBody:body isHTML:YES];
// Problem here:
[self.window presentModalViewController:pickerMail animated:YES];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
// Problem here:
[self.window dismissModalViewControllerAnimated:YES];
//NSLog(#"mail was sent");
}
The problem is in self.window , which is not the right way to access this from the delegate,
I still want to have the mail element in the delegate as all views can call the error alert, and I would like to have only one place for this mechanism.
How should I do it from inside the delegate, what should replace the self.window?

Perhaps reimplementing popErrorWindow: and mailIt: in a category on UIViewController. This way you have access to the top-level view controller to call presentModalViewController and dismissModalViewControllerAnimated on.
Alternatively you can do this in a subclass of UIViewController and then make your other custom view controller's subclass of that. The downside to this method is when you have subclasses of classes other than UIViewController

- (void)mailComposeController:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError *)error
{
[controller dismissModalViewControllerAnimated:YES];
}
EDIT :
The - (void)presentModalViewController:(UIViewController *)vc and - (void)dismissModalViewControllerAnimated:(BOOL)animated methods are an UIViewController instance method, so you cannot use it with an UIWindow.
In order to present your mail controller with a nice animation, you can do that :
UIViewController *aController = self.navigationController.presentedViewController;
[aController presentModalViewController:pickerMail animated:YES];

Related

Email Signature App Iphone

I am making an email signature application that allows user to make signatures and use them to send with emails, Their is signature name(Text Field), content(Text View) and image(Image View) and i am saving them in Database so that if the user selects the signature name from the table view that is on the second view the preview will show up on the same view like if i select signature 1 from table view then in preview section the signature image should show up with the signature content in (Text View), and then on the same view we press send(Button) the text and image from the Text View of preview section will be copied to clipboard and then in third view i can paste it in the message section and send the email, is it possible to do that if yes how can i implement it or any other idea how to do this ?
i have this one method for send email with image and message .. just add MFMessageComposeViewControllerDelegate in .h file and add framework MessageUI.framework in your project
-(void)sendMailWithImage:(NSString *)message Image:(UIImage *)image{
if ([MFMailComposeViewController canSendMail])
{
UIImage *tempImageSave=image;
MFMailComposeViewController *mailComposeViewController = [[MFMailComposeViewController alloc] init];
NSString *mailBody = message;
NSData *imageData = UIImagePNGRepresentation(tempImageSave);
[mailComposeViewController addAttachmentData:imageData mimeType:#"image/png" fileName:#"Testing"];
[mailComposeViewController setMessageBody:mailBody isHTML:NO];
mailComposeViewController.mailComposeDelegate = self;
[self presentViewController:mailComposeViewController animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"e-Mail Sending Alert"
message:#"You can't send a mail"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
and this bellow method is delegate method of MFMessageComposeViewControllerDelegate
#pragma mark - MFMessage Delegate
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
if (result == MFMailComposeResultSent)
{
NSLog(#"\n\n Email Sent");
}
[self dismissViewControllerAnimated:YES completion:nil];
}
i hope this help you...

Frustrating UIWebView Delegate Crash issue

I've created an ARC Application that run's perfect. It's got a UINavigationController that I use to push through the views and everything runs fine.
I'm converting the Application to iPad and i've decided to show one of the views as a popover. (I don't like UIPopoverController so i've created my own basic popup). It's added to the view as follows..
MyViewController *hotelinf = [[MyViewController alloc]
initWithNibName:#"MyViewController_iPad" bundle:nil];
[self.view addSubview:hotelinf.view];
The view is added as a subview fine. The view i'm adding contains a UIWebView that has the usual delegate methods in it, but when the view tries to access one of the delegates it simply crashes.
*** -[MyViewController respondsToSelector:]: message sent to deallocated instance 0x7917b90
Specifically, it crashes on this line..
[self.webView loadHTMLString:stringResponse baseURL:nil];
I've displayed views (and UINavigationControllers) as subViews many of times without any issues, although none of them included a UIWebView delegate. I'm guessing I have to set the delegate of my UIViewController istance but i'm not sure how. It's also worth noting that if I push the view in my existing UINavigationController it calls and loads the HTML fine, which surely means it has nothing to do with the code of the view itself.
Any help would be greatly appreciated! Here is the code (in addition to above that shows the controller)..
.h
#interface MyViewController : UIViewController <UIWebViewDelegate, UIActionSheetDelegate> {
//Unrelated IBOutlets
}
#property (nonatomic, strong) UIWebView *webView;
#end
.m
#implementation MyViewController
#synthesize webView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView = [[UIWebView alloc]initWithFrame:CGRectMake(317,283,393,354)];
self.webView.delegate = self;
[self.view addSubview:self.webView];
[NSThread detachNewThreadSelector:#selector(getHTMLString) toTarget:self withObject:nil];
}
-(void)getHTMLString {
#autoreleasepool {
//Download a valid HTML String
[self performSelectorOnMainThread:#selector(loadHTML) withObject:nil waitUntilDone:NO];
}
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView = nil;
}
-(void)loadHTML {
self.webView.opaque = NO;
self.webView.backgroundColor = [UIColor clearColor];
if ([stringResponse isEqualToString:#""]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Could not connect to XXXXX.com. Please verify you are connected to a working 3G/WIFI Network." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
} else {
//it crashes here only when loaded as a subview - the first access to the delegate
[self.webView loadHTMLString:stringResponse baseURL:nil];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self stopIndicator];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
if (error.code == NSURLErrorCancelled) return; // this is Error -999
[self stopIndicator];
// report the error inside the webview
NSString* errorString = [NSString stringWithFormat:
#"<html><center><font size=+10 color='black' face='Helvetica'>An error occurred:<br>%#</font></center></html>",
error.localizedDescription];
[self.webView loadHTMLString:errorString baseURL:nil];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Cannot load URL."
message:#"You have a connection failure. Please verify you are connected to a WIFI or 3G enabled Network."
delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
#end
The issue has nothing to do with the UIWebView, rather with your controller class. Indeed,
MyViewController *hotelinf = [[MyViewController alloc]
initWithNibName:#"MyViewController_iPad" bundle:nil];
[self.view addSubview:hotelinf.view];
You are allocating the controller and assigning it to a local variable; then you add the controller's view as subview to your current view. Doing that, that view is retained, but what happens to the controller object itself? Are you releasing it? Or it leaks (since it is assigned to a local variable)?
This possibly explains why when later the respondsToSelector method is called, the controller has already been deallocated...
A way to fix this is creating a new property or an ivar in your main controller class and store MyViewController in there. Don't forget to release it in dealloc.
I would also suggest another thing. In:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView = nil;
}
set the webView delegate to nil before releasing the view:
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
self.webView.delegate = nil;
self.webView = nil;
}
And I would also possibly review the reason why you release the webView in viewDidDisappear. On the other hand you allocate it in viewDidLoad. This asymmetry is dangerous, since whenever the main view disappears (for any reason) the webView will be removed and when the view reappears, it is not there anymore.
Better add all the delegate methods. You havent added the first two. Most probably, your code is crashing when message webViewDidStartLoad is sent
– webView:shouldStartLoadWithRequest:navigationType:
– webViewDidStartLoad:
– webViewDidFinishLoad:
– webView:didFailLoadWithError:

how to call one view controller to another view controller in Xcode 4.2

i have two view controller firstviewconroller and secondviewcontroller. i have alert view in firstviewconroller now i want to goto second secondviewcontroller. clicking alert view button. guide me how to call secondviewcontroller using code.i'm new to this stuff.
here is my alert view code.
-(IBAction)enter:(id) sender{
UIAlertView *alertBox=[[UIAlertView alloc]initWithTitle:#"ThinkTax!" message:#"0.0" delegate:self cancelButtonTitle:#"Button 1" otherButtonTitles:nil];
[alertBox addButtonWithTitle:#"Sve"];
[alertBox addButtonWithTitle:#"Button 3"];
if(FALSE)
{
[alertBox addButtonWithTitle:#"Button 4"];
}
[alertBox show];
[alertBox release];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"details"])
{
UIViewController *secondViewController = [[Hello_WorldViewController alloc] initWithNibName:#"<Hello_WorldViewController >" bundle:nil];
[self Page3:secondViewController animated:YES];
[secondViewController release];
NSLog(#"Button details was selected.");
}
else if([title isEqualToString:#"mail"])
{
NSLog(#"Button mail was selected.");
}
else if([title isEqualToString:#"close"])
{
NSLog(#"Button close was selected.");
}
}
now its showing console output like this.i don't know where i'm doing wrong.
-[Page3 Page3:animated:]: unrecognized selector sent to instance 0x8d26ba0
Hello World[5961:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Page3 Page3:animated:]: unrecognized selector sent to instance 0x8d26ba0'
This is the code,
UIViewController *secondViewController = [[SecondViewControllerClass alloc] initWithNibName:#"<name of xib>" bundle:nil];
[self presentModalViewController:secondViewController animated:YES];
[secondViewController release];
There are several questions with the same topic, you should have search before posting this question.
This is Very Simple You just have to create an Object of the NextViewController on which you want to go and call presentModalViewController on that.. like this.:-
in FirstVC.h:-
#class SecondVC;
SecondViewController *viewController;
inFirstViewController.m:-
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"details"])
{
viewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self presentModalViewController:viewController animated:YES];
[viewController release];
}
else if([title isEqualToString:#"mail"])
{
NSLog(#"Button mail was selected.");
}
else if([title isEqualToString:#"close"])
{
NSLog(#"Button close was selected.");
}
}
And Yes What KingofBliss Said is very true. Please make it in Notice.
Good Day.
i did this but app crashes on the line
if([str isEqualToString:#"xxxxx"])
{
if([str1 isEqualToString:#"xxxxx"])
{
FirstListView *ab=[[FirstListView alloc]initWithNibName:#"FirstListView" bundle:nil];
[self presentModalViewController:ab animated:NO];//here app crashes
}
}
else
{
user.text=#"Wrong User";
password.text=#"";
}
which i have a login screen
and on the FirstListView i have two table views.
having no idea why the app crashes.

load a different nib if phone is not connected to internet

I use Apple's Reachability class and it's working fine using an alert to tell the user that the connection is not available or the connection is lost. However, I want to change the alert to something more visual. I want to load a nib that tells the user no active connection is present but the nib is not loading. I also tried loading my other nibs but it also doesn't load the nib.
- (BOOL) checkNetworkStatus:(NSNotification *)notice
{
// called after network status changes
NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
switch (internetStatus)
{
case NotReachable:
{
NSLog(#"The internet is down.");
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"No Internet Connection" message:#"You are currently not connected to a WI-FI or cellular Data.\nPlease make sure you are connected." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
//NoConnection *noConn = [[NoConnection alloc] initWithNibName:#"NoConnecton" bundle:nil];
//[self presentModalViewController:noConn animated:NO];
//[NoConnection release];
self.isConnected = NO;
return NO;
break;
}
//more cases.........
the alert part is working just fine but the part for loading the nib is not. can you tell me whats wrong here? I'm calling this function in viewWillAppear. Thanks!
You can do the following:
if ( ! isConnected )
{
NoConnection *noConn = [[NoConnection alloc] initWithNibName:#"NoConnecton" bundle:nil];
[self presentModalViewController:noConn animated:NO];
[NoConnection release];
}
The code you have presented should work, sow the problem must be somewhere else probably in the nib - linking, you might have forgot to link something to the nib file.
try this
[self.navigationController presentModalViewController:noConn animated:YES];
Does your nib has NoConnection as a File's Owner (I guess NoConnection is a subclass of UIViewController, check it. I'll call this NoConnectionViewController bellow because you should name it like that for no mistake) ?
Is the file's owner view property linked with the graphical view ? Check it.
Are you working without status bar at top of the window ? That could be a problem.
Are your here inside a modalViewController ? If yes, your code won't work, you must use instead :
NoConnectionViewController* nextWindow = [[NoConnectionViewController alloc] initWithNibName:#"NoConnecton" bundle:nil]; // Check your nib name here, seems to be a mistake
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:nextWindow];
[self presentModalViewController:navController animated:YES];
[navController release];
[nextWindow release];
You need to use the delegate method of alert view
#pragma mark - AlertView Delegates
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(alertView.tag == 1)
{
NoConnection *noConn = [[NoConnection alloc] initWithNibName:#"NoConnecton" bundle:nil];
[self presentModalViewController:noConn animated:NO];
[NoConnection release];
}
}
don't forget to assign tag value of alertView to 1.
and also dont forget to conforms to the UIAlertViewDelegate protocol
Happy Coding :)

iphone navigationController : wait for uialertview response before to quit the current view

I have a view with a back button managed with a navigation controller and I want to check if a file has been saved when the user click on the back button.
If the file has been saved you go back in the previous view, else a uialertview ask you if you want to save the file or not.
So I did that but the view disapear and the alertview appear after.
-(void)viewWillDisappear:(BOOL)animated {
if(!self.fileSaved){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"" message:#"Save the file?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes",nil];
[alert show];
[alert release];
}
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0:
NSLog(#"NO");
break;
case 1:
NSLog(#"yes");
break;
default:
break;
}
}
When viewWillDisappear is called, it's already too late. You should intercept the back button earlier on. I have never done it, but my suggestion is to set the delegate on the navigationBar property in your viewDidAppear method:
// save the previous delegate (create an ivar for that)
prevNavigationBarDelegate = self.navigationController.navigationBar.delegate;
self.navigationController.navigationBar.delegate = self;
Don't forget to set it back in viewWillDisappear:
self.navigationController.navigationBar.delegate = prevNavigationBarDelegate;
Then intercept the shouldPopItem method:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if(!self.fileSaved) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"" message:#"Save the file?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes",nil];
[alert show];
[alert release];
return NO;
}
if ([prevNavigationBarDelegate respondsToSelector:#selector(navigationBar:shouldPopItem:)])
return [prevNavigationBarDelegate navigationBar:navigationBar shouldPopItem:item];
return YES;
}
And in the YES handler for the dialog, manually pop the controller:
[self.navigationController popViewController:YES];
You must subclass UINavigationController for this to work. Then override - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item .
You should set up a custom Delegate protocol that your view controllers adopt and, if you allow it to pop, call your [super navigationBar shouldPopItem:], else, return NO to the above method.
Wouldn't it be easier just to add a left button item as in the following:
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:#selector(saveThisDate)];
self.navigationItem.leftBarButtonItem = backButton;
[backButton release];
To follow up on nobre response and as Jon mentionned it, the best way is to subclass UINavigationController.
The easiest way and fastest way to acheive this :
Modify the class of your navigation controller in Interface Builder to inherit from CustomNavigationControllerDelegate
Implement the CustomNavigationControllerDelegate protocol in your UIViewController
#interface YourViewController <CustomNavigationControllerDelegate>
#pragma mark - UINavigationBar Delegate Methods
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:cancel otherButtonTitles:ok, nil];
alert.tag = kpopup_back;
[alert show];
return NO;
}
Register your controller as the delegate
#pragma mark - viewWillAppear
- (void) viewWillAppear:(BOOL)animated
{
((CustomNavigationController*)self.navigationController).customDelegate = self;
}
Finally and important part, REMOVE the delegate (to avoid to re-trigger yourself on the pop) and pop the controller yourself in the the UIAlertViewDelegate
case kpopup_back :
{
if(buttonIndex != 0) //OK
{
((CustomNavigationController*)self.navigationController).customDelegate = nil;
[self.navigationController popViewControllerAnimated:YES];
}
}
break;
It works flawlessly on my side, hope it can help.
Here are the sources :
CustomNavigationControllerDelegate.h
#import <UIKit/UIKit.h>
#protocol CustomNavigationControllerDelegate <NSObject>
#optional
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
#end
#interface CustomNavigationController : UINavigationController
#property (nonatomic, retain) id<CustomNavigationControllerDelegate> customDelegate;
#end
CustomNavigationControllerDelegate.m
#import "CustomNavigationController.h"
#interface CustomNavigationController ()
#end
#implementation CustomNavigationController
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
if (_customDelegate && [_customDelegate respondsToSelector:#selector(navigationBar:shouldPopItem:)]) {
return [_customDelegate navigationBar:navigationBar shouldPopItem:item];
}
return YES;
}
#end