0

I trying to write rhodes native extension extension for opening iOS MailComposer. Now code "works", but MFMailComposeViewController not displaying and xcode shows warning:

Attempt to present <MFMailComposeViewController: 0x12b60840> on <Iosmailto: 0xc1898d0> whose view is not in the window hierarchy!

I read that UIViewControllers must be in hierarchy, but i can't provide this from Rhodes ruby code or clear-C extension wrapper. Now i'm trying to present my UIViewController with MFMailComposeController from [UIApplication sharedApplication].keyWindow.rootViewController but mail composer not show yet.

interface from iosmailto.h:

@interface Iosmailto : UIViewController<MFMailComposeViewControllerDelegate>
{
}
    @property(nonatomic, assign) id delegate;
    //-(IBAction)send_mail:(id)sender;
@end

implementation from iosmailto.m:

@implementation Iosmailto

    - (void)viewDidLoad {
        [super viewDidLoad];
        [self send_mail];
    }

    - (void)send_mail {
        if ([MFMailComposeViewController canSendMail]) {

            MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
            composer.mailComposeDelegate = self;
            [composer setSubject:[NSString stringWithUTF8String:subj]];

            NSArray *recipients_array = [NSArray arrayWithObject:[NSString stringWithUTF8String:recipients]];

            [composer setToRecipients:recipients_array];

            NSString *composerBody = [NSString stringWithUTF8String:message];
            [composer setMessageBody:composerBody isHTML:NO];

            [composer setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
            [self presentModalViewController:composer animated:YES];

            [composer release];
        } else {

            NSLog(@"Device is unable to send email in its current state.");
        }
    }
    /* some unnecessary for this question methods */

@end

And C function defined in iosmailto.m thats called from Rhodes:

// find root vc
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

// find topmost vc
while (topController.presentedViewController) {
    topController = topController.presentedViewController;
}

iosmailer = [[Iosmailto alloc] init];

iosmailer.delegate = topController;
[topController presentViewController:iosmailer animated:YES completion:nil];

This app is not for AppStore. Hacks is welcome if needed.

Update init for Iosmailto:

- (id)init
{
   self = [super initWithNibName:nil bundle:nil];
   return self;
}

Update 2 The short version of this code (without UIViewController wrapper) was my starting point. That's don't work too. And this have the same warning and one more:

UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (topController.presentedViewController) {
    topController = topController.presentedViewController;
}
if ([MFMailComposeViewController canSendMail]) {
    MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
    composer.mailComposeDelegate = (id<MFMailComposeViewControllerDelegate>)topController ;

    [composer setSubject:[NSString stringWithUTF8String:subj]];
    NSArray *recipients_array = [NSArray arrayWithObject:[NSString stringWithUTF8String:recipients]];
    [composer setToRecipients:recipients_array];
    NSString *composerBody = [NSString stringWithUTF8String:message];
    [composer setMessageBody:composerBody isHTML:NO];
    [composer setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
    [topController presentModalViewController:composer animated:YES];

    [composer release];
} else {
}
rootatdarkstar
  • 1,486
  • 2
  • 15
  • 26
  • What's your init method look like for Iosmailto? You'll want to be sure that you either call initWithNib: (defined in UIViewController, inherited by your subclass) or make sure your custom init method calls [super initWithNib:] – Idles Jun 20 '13 at 21:15
  • Made update with init – rootatdarkstar Jun 20 '13 at 21:47
  • Made update about code without wrapper – rootatdarkstar Jun 20 '13 at 22:51
  • Use the code from Update2. Does your topController in that situation actually implement the `MFMailComposeViewControllerDelegate` protocol? If so, just cast it to `id` before assigning it. – Idles Jun 20 '13 at 22:54
  • And if it doesn't implement the protocol, then try just not assigning a delegate. – Idles Jun 20 '13 at 22:55
  • In both cases still the same warning _Attempt to present on whose view is not in the window hierarchy!_ – rootatdarkstar Jun 20 '13 at 23:04

2 Answers2

5

Use this code to present view controller

[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:composer
                                                                                                     animated:YES
                                                                                                   completion:nil];
Desert Rose
  • 3,376
  • 1
  • 30
  • 36
1

Ok I think the problem is that your UIViewController doesn't have anything in its view property because you aren't using a .xib file to initialize it. See this question which programmatically creates a UIView and assigns it to the UIViewController's view property. I think that's the right way to go. See the implementation of their -(void)loadView method.

Your use-case is also a little strange, since it looks like your Iosmailto UIViewController doesn't have any content, and you're just using it as a wrapper around MFMailComposeViewController--you might consider reimplementing your C method to directly create a MFMailComposeViewController without the unnecessary layer of indirection of this unnecessary UIViewController that doesn't display anything itself.

Community
  • 1
  • 1
Idles
  • 1,131
  • 5
  • 9