Подтвердить что ты не робот

Приложение iOS замерзает на PushViewController

Мой навигационный контроллер периодически останавливается при нажатии. Кажется, он добавляет новый контроллер представления в стек, но анимация никогда не происходит. У меня также есть два других контейнера, на которых хранятся контролеры на экране, и я могу нормально взаимодействовать с ними обоими после того, как контроллер навигации замерзает. Очень интересно, если я попытаюсь нажать другой контроллер представления на стек контроллера навигатора, я заметил, что на вершине стека есть дополнительный контроллер представлений (контроллер представления, который я нажал изначально, чтобы заморозить контроллер навигации). Поэтому, если я нахожусь на главном экране (мы будем называть его VC-Home), и я пытаюсь нажать новый вид (VC-1), и он зависает, затем я пытаюсь нажать новое представление (VC-2), это то, что я вижу в текущем стеке перед нажатием:

{ [VC-Home, VC-1] }

и после вызова pushViewController он остается тем же; VC-2 не добавляется в стек.

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

Я создаю новый контроллер представления из раскадровки, позвонив UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController"), поэтому я не думаю, что там есть какие-то проблемы. Я также не переопределяю pushViewController на панели навигации. Некоторые уникальные вещи о моем приложении - это очень высокое изображение с высоким разрешением (с помощью SDWebImage для управления этим), и у меня всегда есть три контейнера на экране одновременно (один контроллер навигации, один контроллер просмотра для поиска и один интерактивный желоб/боковое/слайд-меню).

Потребление процессора низкое, а использование памяти в норме (стабильно около 60-70 МБ на устройстве, когда происходят зависания).

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

Обновление

Нет никакого уникального кода для UINavigationController, так как я просто нажимаю с помощью pushViewController(). Вот код, который его вызывает:

func didSelectItem(profile: SimpleProfile) {
     let vc = UIStoryboard.profileViewController()
     vc.profile = profile
     navigationController?.pushViewController(vc, animated: true)
}

ViewController, который я нажал, имеет следующий код в viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    button.roundView()

    if let type = profile?.profileType {
        //load multiple view controllers into a view pager based on type 
        let viewControllers = ProfileTypeTabAdapter.produceViewControllersBasedOnType(type)
        loadViewPagerViews(viewControllers)

        let topInset = headerView.bounds.height + tabScrollView.contentSize.height
        if let viewPager = viewPager {
            for view in viewPager.views {
                if let tempView = view as? PagingChildViewController {
                    tempView.profile = fullProfile
                    tempView.parentVCDelegate = self
                    tempView.topInset = topInset
                }
            }
        }
    }
}

func loadViewPagerViews(viewControllers: [UIViewController]) {
    viewPager?.views = viewControllers
    viewPager?.delegate = self

    //loading views into paging scroll view (using PureLayout to create constraints)
    let _ = subviews.map { $0.removeFromSuperview() }
    var i = 0
    for item in views {
        addSubview(item.view)
        item.view.autoSetDimensionsToSize(CGSize(width: tabWidth, height: tabHeight))
        if i == 0 {
            item.view.autoPinEdgeToSuperviewEdge(.Leading)
        } else if let previousView = views[i-1].view {
            item.view.autoPinEdge(.Leading, toEdge: .Trailing, ofView: previousView)
        }
        if i == views.count {
            item.view.autoPinEdgeToSuperviewEdge(.Trailing)
        }
        i += 1
    }

    contentSize = CGSize(width: Double(i)*Double(tabWidth), height: Double(tabHeight))
}

Обновление 2

Наконец-то я снова замолчал. Приложение было в фоновом режиме, и я вернул его и попытался нажать на контроллер представления в стеке, когда он застыл. Я заметил, что происходит анимация. У меня есть scrollview в верхней части страницы, через которые через каждые 10 секунд просматривается его содержимое (подумайте, что приложение хранит верхний баннер). На этом замораживании я заметил, что баннер был средней анимацией.

Здесь функция прокрутки из моего UIScrollView, которая вызывается каждые 10 секунд:

func moveToNextItem() {
    let pageWidth: CGFloat = CGRectGetWidth(frame)
    let maxWidth: CGFloat = pageWidth * CGFloat(max(images.count, profileImages.count))
    let contentOffset: CGFloat = self.contentOffset.x
    let slideToX = contentOffset + pageWidth

    //if this is the end of the line, stop the timer
    if contentOffset + pageWidth == maxWidth {
        timer?.invalidate()
        timer = nil
        return
    }

    scrollRectToVisible(CGRectMake(slideToX, 0, pageWidth, CGRectGetHeight(frame)), animated: true)
}

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

Я также перепроверял стек, и такая же ситуация, как описано выше, по-прежнему существует, когда [VC-Home, VC-1] - это стек, а VC-2 не нажимается. Я также прошел переменные VC-1, и все загрузилось (вызовы данных и загрузки изображений).

Обновление 3

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

4b9b3361

Ответ 1

Мы столкнулись с той же проблемой пару недель назад. И для нашей проблемы мы сузили ее до left-edge pop gesture recogniser. Вы можете попробовать и проверить, можете ли вы воспроизвести эту проблему, используя следующие шаги.

  • Попробуйте использовать жест позывного левого края, если под ним нет контроллеров представления (например, на контроллерах корневого представления, вашем контроллере VC-Home)
  • Попробуйте щелкнуть по любым элементам пользовательского интерфейса после этого.

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

Для получения дополнительной информации обратитесь к этому вопросу. Ниже приведен код ссылки для облегчения ссылки.

- (void)navigationController:(UINavigationController *)navigationController
   didShowViewController:(UIViewController *)viewController
                animated:(BOOL)animate
{
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])
{
        if (self.viewControllers.count > 1)
        {
            self.interactivePopGestureRecognizer.enabled = YES;
        }
        else
        {
            self.interactivePopGestureRecognizer.enabled = NO;
        }
    }
}

Ответ 2

Великий ответ от @Penkey Suresh! Спас мой день! Здесь версия SWIFT 3 с небольшим добавлением, которая сделала меня для меня:

    func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {


    if (navigationController.viewControllers.count > 1)
    {
         self.navigationController?.interactivePopGestureRecognizer?.delegate = self
        navigationController.interactivePopGestureRecognizer?.isEnabled = true;
    }
    else
    {
         self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
        navigationController.interactivePopGestureRecognizer?.isEnabled = false;
    }
}

Не забудьте добавить UINavigationControllerDelegate и установить navigationController?.delegate = self Еще одна важная часть - назначить interactivePopGestureRecognizer для себя или для nil соответственно.

Ответ 3

Я думал о прерывистом замораживании, основной теме и SDWebImage.

Предполагая, что вы используете изображение, которое вы загрузили из downloadImageWithURL: параметры: progress: completed: завершенный блок. Если это так, убедитесь, что вы отправляете основную очередь перед использованием изображения.

Если вы используете SDWebImageDownloader напрямую, блок завершения (как вы отметили) будет вызван в фоновом режиме, вы можете исправить его с помощью dispatch_async в основной очереди от завершения.

В противном случае вы можете использовать: SDWebImageManager downloadImageWithURL: опции: progress: completed: (метод, который вызывает блокировки завершения в главной очереди).

Если проблема сохраняется (просто потому, что вы говорите о "некоторых уникальных вещах о моем приложении, это очень тяжелый образ" ), посмотрите также Общие проблемы в основном из-за проблем с Резервное копирование изображений.

Добавьте к вашему чеку также этот код с хорошим кодом:

import UIKit.UINavigationController

public typealias VoidBlock = (Void -> Void)

public extension UINavigationController  
{
    public func pushViewController(viewController: UIViewController, animated: Bool, completion: VoidBlock) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        self.pushViewController(viewController, animated: animated)
        CATransaction.commit()
    }
}

возможно, может помочь понять, завершится ли pushViewController, если закончите с ожиданием всех viewControllers.

Еще один тест, который я пытаюсь сделать, - это запустить приложение с iOS 8.x и iPhone 6+, потому что есть некоторые issues в проекте pureLayout вокруг iOS 9. Можете ли вы отправить отзывы об этом тесте?

У меня есть подозрение и в реальном измерении прокрутки перед действием pushview, можете ли вы проанализировать текущий вид проверку иерархии представлений?

Ответ 4

В основном разделе

dispatch_async(dispatch_get_main_queue()){

UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController")
// your code

}

Ответ 5

Проверьте, есть ли в вашем BaseNavigationViewController какие-либо ненужные коды, подобные приведенным ниже:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

Здесь у меня есть пример кода, который воспроизводит эту проблему (приложение зависает при нажатии VC), и вы должны воспроизвести его, выполнив следующие действия:

  • Попробуйте использовать жест со смещением (влево | вправо), когда под ним нет контроллеров представления (т.е. на контроллерах корневого представления, контроллере VC-Home)
  • Попробуйте нажать на любые элементы пользовательского интерфейса после этого (что подтолкнет вас к следующему ViewController).

Образец кода: https://github.com/aliuncoBamilo/TestNavigationPushBug