2009-06-05 15 views
21

Tengo un tabBarController con dos pestañas, la primera de las cuales contiene una instancia de NavigatorController. El navegadorController se inicia con un viewController personalizado "peersViewController" que enumera todos los pares de red en un tableView. Al seleccionar un par, se inserta una instancia de "FilesListViewController" (que lista los archivos en el directorio c: \) en la pila de navigationController.UINavigationController popToRootViewController, y luego empujar inmediatamente una nueva vista

En este filesListViewController tengo un botón para que navegue para decir el directorio de documentos. Para ello había Telegrafié la interfaz para llamar a un gotoDirectory: (NSString *) método de la ruta en el RootViewController:

- (void)gotoDirectory:(NSString*)path { 
    [[self navigationController] popToRootViewControllerAnimated:YES]; 
    NSArray *files = [self getFilesFromPeerAtPath:path]; 
    FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files]; 
    [[self navigationController] pushViewController:filesVC animated:YES]; 
    [filesVC release]; 
} 

Sin embargo, cuando se presiona el botón, el navigationController hizo estallar mi punto de vista al controlador de vista raíz , pero entonces el FilesListViewController que instalé no apareció. Del registro, sé que el método personalizado initWithFiles fue realmente llamado y que cosas de la red pasaron para obtener los nombres de los archivos.

Algo más es confuso sobre esto. Intenté hacer clic en la segunda pestaña y luego volver a la primera pestaña, ¡y huala! los nombres de archivo que necesitaba están allí. Parece que los datos y los archivosListViewController se insertaron en la pila navigatorController, pero la pantalla no se actualizó sino que se detuvo en la pantalla de rootViewController (peersViewController).

¿Estoy haciendo algo mal?

--Ben.

- Editado como 15 minutos después de publicar la pregunta. Encontré una solución alternativa, pero me molesta que pop y luego push no funcionen.

- (void)gotoDirectory:(NSString*)path { 
    PeersListViewController *rootViewController = (PeersListViewController*)[[[self navigationController] viewControllers] objectAtIndex:0]; 
    [[self navigationController] setViewControllers:[NSArray arrayWithObject:rootViewController]]; 
    FilesListViewController *filesVC = [[FilesListViewController alloc] initWithFiles:files]; 
    [[self navigationController] pushViewController:filesVC animated:YES]; 
    [filesVC release]; 
} 

No parece como el navigationController debe eludirse esta manera, y probablemente tendría que liberar a todos los viewControllers que estaban en la pila de originales. Sin embargo, esto funciona en el simulador de iPhone 3.0.

Sin embargo, si estoy usando este código, ¿cómo debería manejarse la liberación de memoria? ¿Debería obtener el NSArray original de viewcontrollers y liberar todo?

Respuesta

10

Tengo un problema muy similar (pero sin usar la pestaña).

Obtuve tres viewController: main (root), forma y resultado. cuando la pila es UINavigationController

"principal -> resultado"

en un btnClick hago un popToRootViewControllerAnimated entonces la pulsación de un formViewCtrl. el fin de tener

"principal -> forma"

el título barra de navegación y de etiquetas de teclas son correctos y el evento de la formViewCtrl se llaman. PERO, todavía veo la vista principal.

Aquí está mi "solución"

Después de hacer algunas pruebas, descubrí que sin la animación para ir a la rootViwCtrl este trabajo bien. Entonces solo uso la animación para presionar viewCtrl.

iPhone 3.0, problema encontrado en el simulador del dispositivo &.

Si recibo algo nuevo, actualizaré/comentaré mi publicación.

+2

Sí, debe hacer pop sin animación (para que suceda de inmediato) y luego pulsar con animación. Si intenta hacer dos cambios de animación juntos (que llevará tiempo completar), la vista se pondrá en mal estado. – Jason

+0

Exactamente como se describe, esto no funciona para mí. Creo que es un problema de tiempo en los cambios de pila (el código de animación de Apple es muy frágil, está implementado mal) - esta técnica puede funcionar o no dependiendo de cuánto más esté en la pantalla, al parecer. – Adam

1

Encontré una solución, pero no puedo explicar por qué está funcionando: 1. Primero presione el controlador necesario. 2. Luego haz clic en el que quieras.

Esto es totalmente ilógico, pero funciona para mi caso. Para aclarar las cosas, lo estoy usando en el siguiente escenario: Primera pantalla -> Va a la pantalla de carga -> Segunda pantalla Cuando estoy en la segunda pantalla, no quiero tener la pantalla de carga en la pila y cuando vuelva a hacer clic debería ir a la primera pantalla.

Saludos, Vesko Kolev

+0

Esto realmente no debería funcionar. Pero lo hace. En 3.0, he encontrado que el enfoque clásico (manipulación directa de la matriz viewControllers) no siempre funciona como se esperaba, por lo que estoy probando esta solución alternativa. – Adam

76

El problema y la solución a este problema es realmente muy simple.

Llamando [self.navigationController popToRootViewControllerAnimated:YES] establece self.navigationController a nil. Cuando posteriormente llame al [self.navigationController pushViewController:someOtherViewController], está enviando efectivamente un mensaje al nil, que no hace nada.

Para solucionar este problema, simplemente estableció una referencia local a la navigationController y utilizar en su lugar:

UINavigationController * navigationController = self.navigationController; 
[navigationController popToRootViewControllerAnimated:NO]; 
[navigationController pushViewController:someOtherViewController animated:YES]; 

Como se indica por Jason, el popToRootViewController debe llevarse a cabo sin la animación para que esto funcione correctamente.

Gracias a jpimbert on the Apple forums para señalar esto.

+0

¡¡¡Esta funcionó para mí !!! Muchas gracias ... +1 Por Nick! – necixy

+1

¡Ojalá pudiera votar por esto más de una vez! Gran respuesta. – akpb

+0

¡La solución correcta! –

1

La respuesta de Nick Street funciona muy bien si quieres popToRootViewController y luego presionar otro VC.

VC1 -> VC2 -> VC3: pulsa el botón de vuelta de VC3 => VC2, a continuación, VC1, aquí OK

Sin embargo, cuando se empuja VC1 VC2, que a su vez empuja VC3, a continuación, volver a VC1 directamente de VC3 no funciona como se deseaba:

he implementado en -(void)viewWillDisappear:(BOOL)animated de VC3:

-(void)viewWillDisappear:(BOOL)animated{ 

    ... 
    [self.navigationController popToRootViewControllerAnimated:YES]; 
} 

también traté de ponerlo en práctica en el botón "atrás", mismo resultado: al golpear el botón de vuelta de VC3 para volver a VC1: se rompe. El VC real es VC1, pero la barra de navegación sigue siendo VC2. Jugando con otras combinaciones, obtengo VC1's navBar en VC2. Desastre total.

Loda mencionó algo sobre el tiempo. Creo que ese es el problema principal aquí. He intentado un par de cosas, así que tal vez me estoy perdiendo algo aquí, pero esto es lo que funcionó para mí, al fin:

En VC3:

-(void)viewWillDisappear:(BOOL)animated { 

    [super viewWillDisappear:animated]; 
    // notify VC2 
    [[NSNotificationCenter defaultCenter] postNotificationName:backFromV3 object:self]; 
} 

En VC2:

-(void)viewDidLoad { 

    ... 

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(backFromV3) 
               name:@"BackFromV3" 
               object:nil]; 
} 

-(void)backFromV3{ 
    [NSTimer scheduledTimerWithTimeInterval:0.5 
           target:self 
           selector:@selector(backToRootViewController) 
           userInfo:nil 
           repeats:NO]; 
} 

-(void)backToVC1 { 
    self.navigationItem.rightBarButtonItem = nil; 
    [self.navigationController popToRootViewControllerAnimated:YES]; 
} 

Por supuesto, haga la limpieza necesaria.

El temporizador es crítico aquí. Si es 0, se rompe. 0.5 parece estar bien.

Eso funciona perfectamente para mí. Un poco pesado, pero no he podido encontrar nada que solucione el problema.

1

En realidad, puede mantener la animación "Volver atrás", seguida de la animación "Avanzar", básicamente retrasando la animación de inserción hasta que finalice la animación pop. Aquí hay un ejemplo:

(Nota: Tengo una variable NSString llamada "transitionTo" en mi appDelegate que inicialmente está configurada en @ "") ... Primero, configure esa variable en un NSString que pueda detectar más adelante. A continuación, el pop el controlador para darle una transición de pantalla agradable volver a la raíz:

appDelegate.transitionTo = @"Another"; 
[detailNavigationController popToRootViewControllerAnimated:YES]; 

entonces dentro de la clase del RootViewController, utilice el método viewDidAppear:

-(void)viewDidAppear:(BOOL)animated 
{ 
    AppDelegate *appDelegate =(AppDelegate*) [UIApplication sharedApplication].delegate; 
    if([appDelegate.transitionTo isEqualToString:@"Another"]) 
    { 
     [self transitionToAnotherView]; 
     appDelegate.transitionTo = @""; 
    } 
} 

-(void)transitionToAnotherView 
{ 
    // Create and push new view controller here 
    AnotherViewController *controller = [[AnotherViewController alloc] init]; 

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Home" style:UIBarButtonItemStyleBordered target:nil action:nil]; 
    [self.navigationItem setBackBarButtonItem:backButton]; 

    [[self navigationController] pushViewController:controller animated:YES]; 
} 

Así que, básicamente, el pop a la raíz. ..cuando la transición finaliza en "viewDidAppear" ... luego presione la siguiente vista. Ocurrió que mantuve una variable para decirle a qué vista desea hacer la transición (con @ "" que significa no hacer una transición en el caso de que quiera permanecer en esta pantalla).

3

Veo que esta pregunta sobre hacer clic en la raíz y luego presionar un nuevo ViewController es bastante frecuente, y esta publicación se ve mucho, así que quería agregar mi parte para ayudar a otros muchachos nuevos, especialmente aquellos que usan Xcode 4 y un guión gráfico.

En Xcode 4, tiene un guión gráfico. Supongamos que tiene estos controladores de vista: HomeViewController, FirstPageViewController, SecondPageViewController. Asegúrese de hacer clic en cada uno de ellos y nombrar sus identificadores yendo al panel Utilidades-> Inspector de atributos. Diremos que se llaman Inicio, Primero y Segundo.

Estás en casa, luego vas a Primero, luego quieres poder ir a Segundo y puedes presionar el botón Atrás para volver a Inicio. Para hacer esto, desea cambiar su código en FirstPageViewController.

Para ampliar el ejemplo, haga un botón en FirstPageViewController en el guión gráfico. Ctrl-arrastre ese botón hacia FirstPageViewController.m. Ahí, el siguiente código va a lograr el resultado deseado:

// Remember to add #import "SecondPageViewController.h" at the top 
    SecondPageViewController *secondView = [self.storyboard instantiateViewContorllerWithIdentifier:@"Second"]; 
    UINavigationController *navigationController = self.navigationController; 
    NSArray *array = [navigationController viewControllers]; 
    // [array objectAtIndex:0] is the root view controller 
    NSArray *viewControllersStack = [NSArray arrayWithObjects:[array objectAtIndex:0], secondView, nil]; 
    [navigationController setViewControllers:viewControllersStack animated:YES]; 

Básicamente, usted está agarrando los controladores de vista, disponiéndolos en una pila en el orden que desee, y luego tener el uso del controlador de navegación que apilar, navegación. Es una alternativa a empujar y estallar.

Cuestiones relacionadas