简体   繁体   中英

Presenting a modal view from another class (MFMailComposeViewController)

I am trying to create a class who will be responsible to send emails using MFMailComposeViewController so i can use this methods from differences views controls in my app.

This class is called apoio.

In this class have the method bellow.

-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico {

if (![MFMailComposeViewController canSendMail]) {
    // show message box for user that SMS cannot be sent
} else {
    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
    picker.mailComposeDelegate = self;
    [picker setSubject:@"Dashboard"];

    [picker addAttachmentData:_pdfGrafico mimeType:@"application/pdf" fileName:@"grafico.pdf"];

    NSString *emailBody = @"Anexando gráfico";
    [picker setMessageBody:emailBody isHTML:NO];        

     [self presentModalViewController:picker animated:YES];         
       }
}

I have another view controller who calls the apoio method when the user clicks on email button. It is this code bellow

-(IBAction) enviarGraficoPorEmail {

Apoio *apoio = [[Apoio alloc] init];
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}

But i don't know why, the email view doesn't appear. The method is called correct because i debuged and so on.

If i copy the code from apoio method to enviarGraficoPorEmail method, everything works perfect.

But i don't want to do this, beucase ill send emails from others views controller.

What am i doing wrong ??

You could do it a couple of different ways.

Option 1: Pass the calling view controller as a parameter to the class method

-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer] callingController:self];
}

-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[_callingController presentModalViewController:picker animated:YES];
...
}

Option 2: Add a class variable for the calling view controller

-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
apoio.callingController = self;
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}

-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[callingController presentModalViewController:picker animated:YES];
...
}

Then you'd add callingController to your class as a retain property, initialize it to nil, and release it in dealloc.

Option #1 is probably the better approach for your needs.

Thanks a lot!. It is now working but i still have one problem.

I have the method on my generic class who is supposed to be responsible to hide the mailController.

- (void)mailComposeController:(MFMailComposeViewController*)controller      didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error 
{
switch (result)
{
    case MFMailComposeResultCancelled:
        break;
    case MFMailComposeResultSaved:
        break;
    case MFMailComposeResultSent:
        // FAILS
        [self.parentViewController dismissModalViewControllerAnimated:YES];
        break;
    case MFMailComposeResultFailed:
        break;
    default:
        break;
}
[self dismissModalViewControllerAnimated:YES];
}

In the method that creates the mailController have the property

picker.mailComposeDelegate = self;

I tried to change to

picker.mailComposeDelegate = _callingController.self;

I set the MFMailComposeViewControllerDelegate on my generic class already.

But it only works when i copy the method didFinishWithResult and put it on the origin controller, what is not my intention, because i want to put all this code on a generic class.

What am i doing wrong ??

Ok, this is an answer to your second question (which you posted as an answer to your first question).

Here's how I would set it all up:

In your calling view controller .h file:

@interface MyViewController : UIViewController <MyMailDelegate> {
    Apoio *apoio;
}

In your calling view controller .m file:

-(IBAction) enviarGraficoPorEmail {
    apoio = [[Apoio alloc] init];
    apoio.callingController = self;
   [apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}

-(void) enviarCompleto {
    //do whatever here after send email completes
    [apoio release];
}

In your Apoio .h file

@protocol MyMailDelegate
@required
-(void) enviarCompleto;
@end

@interface OfferObject : NSObject {
    UIViewController <MyMailDelegate> *callingController;
}

@property (nonatomic, retain) UIViewController <MyMailDelegate> *callingController;

In your Apoio .m file

-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
    ...
    [callingController presentModalViewController:picker animated:YES];
    ...
}

-(void)mailComposeController:(MFMailComposeViewController*)controller      didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error 
{
    switch (result)
        {
            ...
        }
    [callingController dismissModalViewControllerAnimated:YES];
    [callingController enviarCompleto];
}

Then don't forget to do this on init:

callingController = nil;

And on dealloc:

[callingController release];

Also, don't forget your most important step: up vote both my answers :)

You need to call [self presentModalViewController:picker animated:YES];
from a UIViewController class then it will show you email composer, you can do this, whenever you call from some view controller you can pass its reference and you can change the above line as this

[callingController presentModalViewController:picker animated:YES];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM