2016-04-08 10 views
12

Il mio controller di navigazione a intermittenza si blocca in modalità push. Sembra aggiungere il nuovo controller di visualizzazione allo stack, ma l'animazione non ha mai luogo. Ho anche altri due contenitori che contengono controller di visualizzazione sullo schermo e posso interagire con entrambi senza problemi dopo che il controller di navigazione si è bloccato. La cosa davvero interessante è che se provo a spingere un altro controller di visualizzazione sullo stack del controller di navigazione, ho notato che c'è un controller di visualizzazione extra in cima allo stack (il controller di visualizzazione che ho inizialmente spinto a bloccare il controller di navigazione). Quindi se sono sulla schermata principale (lo chiameremo VC-Home) e provo a premere una nuova vista (VC-1) e si blocca, quindi provo a premere una nuova vista (VC-2), questo è quello che vedo nello stack corrente prima della spinta:L'app iOS si blocca su PushViewController

{ [VC-Home, VC-1] }

e dopo pushViewController è chiamato, rimane la stessa; VC-2 non è aggiunto allo stack.

Da quello che posso dire, il controller di navigazione avvia l'animazione rendendo inattivo il precedente controller di visualizzazione prima dell'inizio dell'animazione, ma l'animazione non viene mai eseguita, lasciando il controller di navigazione in uno stato congelato.

Sto creando il nuovo controller di visualizzazione da uno storyboard chiamando UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") quindi non penso che ci siano problemi lì. Non sto ignorando pushViewController sulla barra di navigazione. Alcune cose uniche della mia app sono che è molto pesante con immagini ad alta risoluzione (usando SDWebImage per gestirlo) e ho sempre tre contenitori sullo schermo contemporaneamente (un controller di navigazione, un controller di visualizzazione per la ricerca e un gutter interattivo/menu laterale/scorrevole).

L'utilizzo della CPU è basso e l'utilizzo della memoria è normale (intorno ai 60-70 MB sul dispositivo quando si verifica il congelamento).

Ci sono idee con ciò che potrebbe causare questo o alcuni suggerimenti per il debug che potrebbero aiutarmi a scoprire il vero problema?

Aggiornamento

Non c'è alcun codice univoco per l'UINavigationController da quando sto solo spingere utilizzando pushViewController(). Ecco il codice che lo chiama:

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

Il ViewController che ho spinto ha il seguente codice nel 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)) 
} 

Update 2

ho finalmente capito a congelare di nuovo. L'app era in background e l'ho richiamata e ho provato a premere un controller di visualizzazione sullo stack quando si è bloccato. Ho notato che si stava svolgendo un'animazione. Ho una scrollview nella parte superiore della pagina che sfoglia il suo contenuto ogni 10 secondi (pensa al banner in alto dell'app store). In questo congelamento, ho notato che il banner era a metà animazione.

Ecco la funzione di scorrimento dalla mia UIScrollView che viene chiamato ogni 10 secondi:

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) 
} 

Non ricordo di aver mai uno stop spinta a causa di un animazione/scorrimento in atto, ma potrei sbagliarmi .

Ho anche ricontrollato lo stack e la stessa situazione descritta sopra è ancora il caso in cui [VC-Home, VC-1] è lo stack e VC-2 non è premuto. Ho anche passato le variabili di VC-1 e tutto è stato caricato (chiamate di dati e carichi di immagini).

Update 3

Questo sta diventando estraneo dal secondo. Ho sovrascritto pushViewController in modo da poter inserire un breakpoint e fare un po 'di debug basato sulla risposta di Alessandro Ornano. Se spingo un controller della vista senza successo, quindi inviare la mia app allo sfondo, inserire un breakpoint nella chiamata pushViewController e riportare l'app, il punto di interruzione viene immediatamente colpito un numero di volte. Se poi continuo oltre tutti i colpi, il controller della vista successivo diventa improvvisamente visibile e l'ultimo controller della vista che ho provato a premere è ora in pila come ultimo controller della vista. Ciò significa che quello che vedo è ancora disabilitato, il che essenzialmente mi colloca nella stessa posizione di prima.

+0

È possibile fornire dettagli sui metodi VC-1 come viewWillAppear, viewDidAppear o viewDidDisappear? Esistono istruzioni nel thread principale che compromettono le costruzioni del layout? –

+0

Sono d'accordo @AlessandroOrnano, sei nella stessa discussione? – bourvill

+0

Sto solo sovrascrivendo viewDidAppear, ma sto solo impostando un bool e portando una sottoview in primo piano. Nessun thread in background lì. Continuerò a cercare qualsiasi cosa in un thread in background che potrebbe essere sospetto e aggiornare la mia domanda se trovo qualcosa. – Maxwell

risposta

25

Abbiamo affrontato lo stesso problema un paio di settimane fa. E per il nostro problema l'abbiamo ridotto a left-edge pop gesture recogniser.Si può provare e verificare se è possibile riprodurre il problema utilizzando i passaggi qui sotto

  • Provare a utilizzare il gesto pop bordo sinistro quando non ci sono controller di vista di sotto di essa (vale a dire sulla vista radice controller, il controller VC-Home)
  • Try facendo clic su qualsiasi elemento dell'interfaccia utente dopo questo.

Se è possibile riprodurre il blocco, provare a disabilitare lo interactivePopGestureRecognizer quando lo stack del controller di visualizzazione ha un solo controller di visualizzazione.

Vedere la domanda this per ulteriori dettagli. Di seguito è riportato il codice dal collegamento per facilità di riferimento.

- (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; 
     } 
    } 
} 
+1

Beh, non è qualcosa! Domani farò alcuni test, ma questo si sta facendo congelare in modo molto coerente. – Maxwell

+0

@Maxwell si. L'ho osservato anche su alcune app famose su App Store. –

+0

Buona scoperta! Grazie per la condivisione. – Maxwell

0

Prova a thread principale

dispatch_async(dispatch_get_main_queue()){ 

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

} 
1

Stavo pensando a intermittenza congelamento, thread principale e SDWebImage.

Supponendo che si utilizza l'immagine è stato scaricato da downloadImageWithURL: opzioni: il progresso: completato: 's blocco completato .. se è così, assicuratevi di spedizione verso la coda principale prima di utilizzare utilizzando l'immagine.

Se si utilizza direttamente SDWebImageDownloader, il blocco di completamento (come specificato) verrà richiamato su una coda in background, è possibile correggerlo utilizzando dispatch_async sulla coda principale dal completamento.

In caso contrario è possibile utilizzare: SDWebImageManager downloadImageWithURL: opzioni: progresso: completato: (metodo che richiama i blocchi di completamento sulla coda principale).

se il problema persiste (solo perché si parla di "..alcuni cose uniche circa la mia app è che è molto pesante immagine ..") sembrano anche Common problems soprattutto l'immagine maniglia aggiornare sanno problemi.

Aggiungi alla tua assegno anche questo bel frammento di codice:

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() 
    } 
} 

forse può aiutare a capire se finitura pushViewController, se finire con tutti i viewControllers attesi ..

Un altro test cerco di fare è quello di avvia l'app con iOS 8.xe iPhone 6+, perché ci sono alcuni issues nel progetto pureLayout su iOS 9. Puoi inviare feedback in merito a questo test?

Ho qualche sospetto anche sulla dimensione reale della vista a scorrimento prima dell'azione pushview, è possibile analizzare la vista corrente tramite examing the view hierarchy?

+0

Sto usando '' 'imageView.sd_setImageWithURL (url)' '' per tutto il mio caricamento dell'immagine che esegue per me il blocco di completamento sul thread principale, quindi non mi aspetto che il congelamento si verifichi lì. – Maxwell

+0

Ho aggiunto un codice snippet, spero sia utile .. Aggiornamento –

+0

: Ho inserito il codice e il blocco di completamento stampa sulla console che la transizione è terminata. Ho bloccato il controller di navigazione, ma posso ancora provare a inserire nuovi controller di visualizzazione nello stack da uno dei miei altri contenitori. Quando lo faccio, viene eseguito il blocco di completamento, ma la dichiarazione di stampa non viene mai visualizzata nella console. – Maxwell

2

Grande answer da @Penkey Suresh! Ho salvato la mia giornata! Ecco un SWIFT 3 versione con una piccola aggiunta che ha fatto la differenza per me:

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; 
    } 
} 

Basta non dimenticare di aggiungere UINavigationControllerDelegate e impostare la Un'altra parte navigationController?.delegate = self importante è quello di assegnare il interactivePopGestureRecognizer per sé o per nil di conseguenza.