iOS dismissModalViewController приводит к EXC_BAD_ACCESS - PullRequest
3 голосов
/ 28 марта 2012

Вызов dismissModalViewController будет периодически вызывать EXC_BAD_ACCESs.

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

Кажется, это не зависит от того, изменился ли код между сборками.

Мы используем симулятор iPhone 5.1 и iPod touch 4-го поколения с установленной iOS 5.1. Такое поведение присутствует как в смоделированном, так и в физическом устройстве

Кто-нибудь видел это раньше? Мы находимся в конце нашего остроумия.

Здесь и то, где представлен модальный контроллер представления, и то, где он уволен:

PaymentStack* paymentStack = 
[[PaymentStack alloc] initWithOrder:[anOrderManager thisOrder] locationState:[appData locationState]
                       successBlock:^{
                           //Push the current order on the history list
                           [[appData ordersHistory] addObject:[anOrderManager thisOrder]];
                           if ([[anOrderManager thisOrder] isEffectivelyEqual:[anOrderManager thisOrder]])
                           {
                               //Allocate a new order
                               [anOrderManager setOrder:[[Order alloc] init]];
                           }
                       }
                    completionBlock:^{

                        [self dismissViewControllerAnimated:YES 
                                                 completion:^{
                                                     NSLog(@"Complete.");
                                                 }];
                    }
                  cancellationBlock:^{
                      [self dismissViewControllerAnimated:YES 
                                               completion:^{
                                                   NSLog(@"Cancellation.");
                                               }];
                  }];
[self presentModalViewController:[paymentStack navigationController] animated:YES];

Вот трассировка стека:

#0  0x00d659ab in -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:] ()
#1  0x00b4ea9c in -[UIViewController _dismissViewControllerWithTransition:from:completion:] ()
#2  0x00b4df91 in -[UIViewController dismissViewControllerWithTransition:completion:] ()
#3  0x00b4ec81 in -[UIViewController dismissViewControllerAnimated:completion:] ()
#4  0x00071135 in __35-[MasterViewController placeOrder:]_block_invoke_0186 at /Users/jake/Documents/Avocado/AvocadoTest1.0/MasterViewController.m:258
#5  0x000515c0 in __91-[PaymentStack initWithOrder:locationState:successBlock:completionBlock:cancellationBlock:]_block_invoke_0 ()
#6  0x000545c8 in __27-[PaymentStack showSuccess]_block_invoke_0230 ()
#7  0x000558cc in -[PaymentCompleteViewController done] ()
#8  0x01a47e99 in -[NSObject performSelector:withObject:withObject:] ()
#9  0x00a8214e in -[UIApplication sendAction:to:from:forEvent:] ()
#10 0x00cc0a0e in -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] ()
#11 0x01a47e99 in -[NSObject performSelector:withObject:withObject:] ()
#12 0x00a8214e in -[UIApplication sendAction:to:from:forEvent:] ()
#13 0x00a820e6 in -[UIApplication sendAction:toTarget:fromSender:forEvent:] ()
#14 0x00b28ade in -[UIControl sendAction:to:forEvent:] ()
#15 0x00b28fa7 in -[UIControl(Internal) _sendActionsForEvents:withEvent:] ()
#16 0x00b28266 in -[UIControl touchesEnded:withEvent:] ()
#17 0x00aa73c0 in -[UIWindow _sendTouchesForEvent:] ()
#18 0x00aa75e6 in -[UIWindow sendEvent:] ()
#19 0x00a8ddc4 in -[UIApplication sendEvent:] ()
#20 0x00a81634 in _UIApplicationHandleEvent ()
#21 0x03dd9ef5 in PurpleEventCallback ()
#22 0x01a1a195 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#23 0x0197eff2 in __CFRunLoopDoSource1 ()
#24 0x0197d8da in __CFRunLoopRun ()
#25 0x0197cd84 in CFRunLoopRunSpecific ()
#26 0x0197cc9b in CFRunLoopRunInMode ()
#27 0x03dd87d8 in GSEventRunModal ()
#28 0x03dd888a in GSEventRun ()
#29 0x00a7f626 in UIApplicationMain ()
#30 0x000025ed in main at /Users/jake/Documents/Avocado/AvocadoTest1.0/AvocadoTest1/main.m:16

Если есть лучший способ, которым я могу отформатировать это для вас, дайте мне знать.

Ответы [ 3 ]

1 голос
/ 04 сентября 2014

Проблема, с которой я столкнулся (с такими же симптомами, как эта), оказалась (после трудного дня отладки!) Следующей ситуацией:

1) Просмотр контроллеров A подарков (с использованием presentViewController: анимированный: завершение :) просмотр контроллера B.

2) Контроллер вида B хранит слабую ссылку на контроллер вида A (ссылка на делегата).

3) Контроллер вида B выполняет метод на контроллере вида A, который в качестве побочного эффекта освобождает контроллер вида A.

4) Контроллер вида B пытается отменить себя, используя:

[self dismissViewControllerAnimated:NO completion:completion];

Часть трудностей в отслеживании этого возникла из-за шага 3) асинхронности. Шаг 4) выполнялся, а шаг 3) еще не закончился. То есть контроллер вида B был освобожден частично через этап 4).

1 голос
/ 28 марта 2012

Когда вы запускаете что-то вроде:

[self dismissViewControllerAnimated:YES 
                         completion:^{
                                     NSLog(@"Complete.");
                                     }];

внутри блока и запустите что-то вроде:

[self presentModalViewController:[paymentStack navigationController] animated:YES];

вне блока невозможно узнать, какая строка кода будет выполняться первой. Иногда это будет dismissViewControllerAnimated:, иногда это будет presentModalViewController:.

Если dismissViewControllerAnimated: запускается первым, тогда viewController, вероятно, получает dealloc'ed, поэтому, когда приложение пытается запустить presentModalViewController: оно отправляет сообщение объекту, которого больше нет, и это, вероятно, является причиной сбоя.

Удачи!

0 голосов
/ 04 сентября 2014

Попробуйте сохранить 2 сильных указателя: один для PaymentStack viewController и один для «себя». Это поможет определить, кто был уничтожен. Добавьте методы "- (void) dealloc" для каждого viewControllers и добавьте точки останова к этим методам. Это поможет обнаружить точку разрушения.

...