2

У меня есть UIViewController, который представляет/увольняет другой контроллер представления с пользовательской анимацией с использованием шаблона transitioningDelegate введенного в прошивке 7.Иногда Краш с клиентами View Controller Переходом

Я заметил в моих Crashlytics лог-файлы, которые этот раздел кода иногда рушится в производстве, и я не смог разобраться, почему. Его никогда не терпел неудачу в моем тестировании и, похоже, затрагивает примерно 10% наших пользователей. iOS 7 и iOS 8, а также iPad, iPhone и iPod.

Heres трассировка стеки из Crashlytics:

Crashed: com.apple.main-thread 
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00014000 

Thread : Crashed: com.apple.main-thread 
0 libobjc.A.dylib    0x303c3f76 objc_msgSend + 21 
1 UIKit       0x25ed0ac5 -[UIViewController _customAnimatorForDismissedController:] + 64 
2 UIKit       0x25ed0927 -[UIViewController _dismissViewControllerWithTransition:from:completion:] + 538 
3 UIKit       0x25e7e4b3 -[UIViewController dismissViewControllerWithTransition:completion:] + 822 
4 UIKit       0x25e7e4b3 -[UIViewController dismissViewControllerWithTransition:completion:] + 822 
5 UIKit       0x25e7e127 -[UIViewController dismissViewControllerAnimated:completion:] + 222 
6 Skin Creator     0x000f38e7 -[SEUSBodySideChooserViewController imageEditViewController:didFinishWithImage:] (SEUSBodySideChooserViewController.m:251) 
7 Skin Creator     0x000ae2e9 -[SEUSImageEditViewController sendFinishedDelegateMethod] (SEUSImageEditViewController.m:409) 
8 Skin Creator     0x000d585f -[SEUSCloseMenuController circleMenu:didSelectItemAtIndex:] (SEUSCloseMenuController.m:69) 
9 Skin Creator     0x000ceb75 -[SEUSCircleMenu menuButtonPressed:] (SEUSCircleMenu.m:203) 
10 UIKit       0x25dec427 -[UIApplication sendAction:to:from:forEvent:] + 70 
11 UIKit       0x25dec3c9 -[UIControl sendAction:to:forEvent:] + 44 
12 UIKit       0x25dd6fcd -[UIControl _sendActionsForEvents:withEvent:] + 584 
13 UIKit       0x25debdf9 -[UIControl touchesEnded:withEvent:] + 584 
14 UIKit       0x25db0b47 _UIGestureRecognizerUpdate + 10158 
15 UIKit       0x25de5afd -[UIWindow _sendGesturesForEvent:] + 784 
16 UIKit       0x25de53cd -[UIWindow sendEvent:] + 520 
17 UIKit       0x25dbbb5d -[UIApplication sendEvent:] + 196 
18 UIKit       0x2602f4e3 _UIApplicationHandleEventFromQueueEvent + 13874 
19 UIKit       0x25dba59f _UIApplicationHandleEventQueue + 1294 
20 CoreFoundation     0x228dd5e7 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14 
21 CoreFoundation     0x228dc9fb __CFRunLoopDoSources0 + 222 
22 CoreFoundation     0x228db079 __CFRunLoopRun + 768 
23 CoreFoundation     0x22828981 CFRunLoopRunSpecific + 476 
24 CoreFoundation     0x22828793 CFRunLoopRunInMode + 106 
25 GraphicsServices    0x29ba9051 GSEventRunModal + 136 
26 UIKit       0x25e1a981 UIApplicationMain + 1440 
27 Skin Creator     0x000ead6f main (main.m:16) 

Точно так же вы можете понять это немного больше [SEUSBodySideChooserViewController imageEditViewController: didFinishWithImage:] является делегатом обратным вызовом, где я распускать контроллер представления.

код я использую, чтобы представить View Controller

_toPixelEditTransitioningDelegate = [[SEUSFadeInTransitioningDelegate alloc] init]; 
_imageEditViewController.transitioningDelegate = _toPixelEditTransitioningDelegate; 
[self presentViewController:_imageEditViewController animated:YES completion:nil]; 

код я использую Уволить View Controller

[viewController dismissViewControllerAnimated:YES completion:nil]; 

Мой Переход делегат

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source 
{ 
    SEUSFadeInTransitioning *transitioning = [[SEUSFadeInTransitioning alloc] init]; 
    return transitioning; 
} 

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed 
{ 
    SEUSFadeInTransitioning *transitioning = [[SEUSFadeInTransitioning alloc] init]; 
    transitioning.reverse = YES; 
    return transitioning; 
} 

Переход объекта, который реализует UIViewControllerAnimatedTransitioning протокол

- (instancetype)init 
{ 
    if (self = [super init]) 
    { 
     _reverse = NO; 
     _duration = 0.25f; 
    } 
    return self; 
} 

- (void)animateToPixelEdit:(id<UIViewControllerContextTransitioning>)transitionContext 
{ 
    UIViewController* overviewVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 
    UIViewController* pixelVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 
    [[transitionContext containerView] addSubview:overviewVC.view]; 
    [[transitionContext containerView] addSubview:pixelVC.view]; 

    pixelVC.view.alpha = 0; 

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^ 
    { 
     pixelVC.view.alpha = 1; 
    } 
    completion:^(BOOL finished) 
    { 
     [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 
    }]; 
} 

- (void)animateToOverview:(id<UIViewControllerContextTransitioning>)transitionContext 
{ 
    UIViewController* pixelVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 
    UIViewController* overviewVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 
    [[transitionContext containerView] addSubview:pixelVC.view]; 
    [[transitionContext containerView] addSubview:overviewVC.view]; 

    overviewVC.view.alpha = 0; 

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^ 
    { 
     overviewVC.view.alpha = 1; 
    } 
    completion:^(BOOL finished) 
    { 
     [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 
    }]; 
} 

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext 
{ 
    return _duration; 
} 

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext 
{ 
    if (self.reverse == NO) 
    { 
     [self animateToPixelEdit:transitionContext]; 
    } 
    else 
    { 
     [self animateToOverview:transitionContext]; 
    } 
} 

Любое замечает что-нибудь, что может пойти не так? Его действительно трудно устранить, так как я не смог воспроизвести авария.

+0

Возможно ли, что imageEditVC вызывает его метод делегирования didFinish дважды, если пользователь несколько раз кратковременно нажимает? – Acey

+0

О, человек. Если это так просто, я не уверен, что я должен чувствовать себя глупо или возбужденно. Ганна проверь это сейчас! –

+0

Не удавалось повторить, что до сих пор я буду котироваться в чеке, чтобы он просто разблокировал и вытолкнул его. В среднем, кто-нибудь видит что-нибудь еще, что потенциально может вызвать его? –

ответ

1

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

0

Я разрешил ошибку, подобную этой, она оказалась ссылкой _toPixelEditTransitioningDelegate, которая была освобождена.

Если вы видите EXEC_BAD_ACCESS, вы можете включить NSZombies, который поможет вам отслеживать объект bad reference'd.

Надеюсь, это окажется полезным для кого-то еще!