Увольнение MFMailComposeViewController вызывает EXC_BAD_ACCESS - PullRequest
4 голосов
/ 01 ноября 2010

Я отображаю MFMailComposeViewController следующим образом:

- (IBAction) contactUs: (id) sender {
    [Tracker trackContactUsPressed: [MFMailComposeViewController canSendMail]];

    if ([MFMailComposeViewController canSendMail] == NO) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Email Error"
                                                        message: @"Email has not been configured on this device.  Please send us an email at\nFOO@BAR.com"
                                                       delegate: self
                                              cancelButtonTitle: @"OK"
                                              otherButtonTitles: nil];
        [alert show];
        [alert release];
    } else {

        MFMailComposeViewController *controller = [[[MFMailComposeViewController alloc] init] autorelease];

        [controller setSubject:@"Comments about FOO"];            

        [controller setToRecipients: [NSArray arrayWithObject: @"FOO@BAR.com"]];
        [controller setMailComposeDelegate: self];

        [[self parentViewController] presentModalViewController:controller animated:YES];
    }
}

Тогда мой делегат выглядит так:

- (void) mailComposeController: (MFMailComposeViewController *) controller didFinishWithResult: (MFMailComposeResult) result error: (NSError *) error {
    [[self parentViewController] dismissModalViewControllerAnimated: YES];
}

Однако, как только делегат вызывается, и представление исчезаетЯ получаю EXC_BAD_ACCESS.Обратный след говорит следующее:

#0  0x00000000 in ?? ()
#1  0x0065a2d9 in -[UIWindowController transitionViewDidComplete:fromView:toView:] ()
#2  0x0044a905 in -[UITransitionView notifyDidCompleteTransition:] ()
#3  0x003f1499 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#4  0x003f132b in -[UIViewAnimationState animationDidStop:finished:] ()
#5  0x02631db0 in run_animation_callbacks ()
#6  0x02631c6f in CA::timer_callback ()
#7  0x0284bf73 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#8  0x0284d5b4 in __CFRunLoopDoTimer ()
#9  0x027a9dd9 in __CFRunLoopRun ()
#10 0x027a9350 in CFRunLoopRunSpecific ()
#11 0x027a9271 in CFRunLoopRunInMode ()
#12 0x0305500c in GSEventRunModal ()
#13 0x030550d1 in GSEventRun ()
#14 0x003cfaf2 in UIApplicationMain ()
#15 0x000023c5 in main (argc=1, argv=0xbfffefcc) at main.m:14

Я не могу понять, что случилось.Насколько я знаю, это работало ранее с 3.x SDK, который мы использовали (мы выпустили его и все!).Теперь с новым SDK (4.1) он, похоже, не работает.Я не уверен, что это связано.

Кто-нибудь знает, что случилось?

Ответы [ 4 ]

8 голосов
/ 10 ноября 2010

Я нашел проблему.

Мы используем библиотеку ShareKit для интеграции Twitter и Facebook. Поскольку у нас уже была своя собственная форма электронной почты, нам не требовался ShareKit для ее обработки, поэтому мы удалили файлы обработки электронной почты ShareKit.

Все было хорошо, за исключением того, что в своей инициализации ShareKit делает это:

SHKSwizzle([MFMailComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:)); 

Где SHKSwizzle в основном заменяет MFMailComposerViewController viewDidDisappear: метод с SHKviewDidDisappear: (не спрашивайте меня, почему ... я думаю, что это ужасно).

Так или иначе, оказывается, что SHKviewDidDisappear был в почтовом обработчике ShareKit, поэтому удаление файла приводит к тому, что код переходит в гиперпространство и ужасно падает. Восстановление файла снова решает проблему.

Тьфу.

Спасибо всем за помощь!

1 голос
/ 01 ноября 2010

Просто догадка, но мне показались странными следующие строки:

[[self parentViewController] presentModalViewController:controller animated:YES];

и

[[self parentViewController] dismissModalViewControllerAnimated: YES];

Правда, я не знаю, как вы расположили контроллеры представлений, но не немного ли необычно напрямую ссылаться на [self parentViewController]? Вы сильно связываете три контроллера представления (вызывающая сторона, родитель и модальное представление); это препятствует повторному использованию контроллера кода / представления (например, если вы хотите повторно использовать один и тот же контроллер представления в другой иерархии представлений в другом месте приложения).

Единственная причина, по которой я могу представить, что вы можете захотеть сделать это, заключается в том, что родителем является UINavigationController / UITabBarController, и поскольку это вид сверху, вы хотите, чтобы этот контроллер представления представлял модальный.

В этом случае я использую:

[[self navigationController] presentModalViewController:controller animated:YES]

Или, что еще лучше, в ситуации с панелью вкладок мой корневой контроллер регистрирует наблюдателя, прослушивающего уведомления, а затем все модалы запускаются из корневого контроллера представления.

Могу ли я получить немного больше информации о вашем стеке представлений? Кроме того, не могли бы вы попробовать один раз просто вызвать «я» вместо родителя и посмотреть, что произойдет?

0 голосов
/ 01 ноября 2010

Если вы хотите закрыть почтовый композитор, лучший способ сделать это так:

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

Таким образом, вам не нужно сильно беспокоиться о контроллере или его родительском элементе или о чем-либо

А также для представления композитора, вместо использования

 [[self parentViewController] presentModalViewController:controller animated:YES];

попробуйте использовать

 [self presentModalViewController:controller animated:YES];
0 голосов
/ 01 ноября 2010

Вероятно, он выходит из-под вас автоматически. Я видел, как это происходит с UIDocumentInteractionController, а также. Лучшее решение, вероятно, состоит в том, чтобы сохранить MFMailComposeViewController в переменной экземпляра и затем освободить его в didFinishWithResult.

...