2012-09-20 27 views
18

Soy bastante nuevo en xcode, y estoy intentando desarrollar una aplicación de muestra que básicamente es una tabla incorporada que tiene muchos niveles. Tengo un plist que almacena las celdas de cada tabla vista. Si las celdas no tienen hijos, entonces quiero poder ir a una vista detallada una vez que se presiona la celda. Eventualmente quiero poder ir a diferentes vistas detalladas dependiendo del tipo de datos. Para hacer esto, creé una vista detallada del guión gráfico, arrastré mi controlador de vista a mi vista detallada para crear un segue "Push" manual y etiqueté el segue "segue1".Creación manual de segue mediante storyboard y xcode

Editar: El código fuente here

Building Manual Segue

siguiente que pueblan lo que supuse que las funciones necesarias para que esto funcione, lo que quiere llamar [self performSegueWithIdentifier:@"segue1" sender:myString]; donde miCadena es el título de la célula I seleccionado.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    //Check the dictionary to see what cell was clicked 
    NSDictionary *dict = [self.tableDataSource objectAtIndex:indexPath.row]; 
    NSString *myString = [dict objectForKey:@"Title"]; 
    NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row]; 

    NSArray *children = [dictionary objectForKey:@"Children"]; 

    //If there is no children, go to the detailed view 
    if([children count] == 0) 
    { 
     [self performSegueWithIdentifier:@"segue1" sender:myString]; 

    } 
    else{ 
     //Prepare to tableview. 
     DrillDownViewController *rvController = [[DrillDownViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]]; 

     //Increment the Current View 
     rvController.CurrentLevel += 1; 

     //Set the title; 
     rvController.CurrentTitle = [dictionary objectForKey:@"Title"]; 

     //Push the new table view on the stack 
     [self.navigationController pushViewController:rvController animated:YES]; 

     rvController.tableDataSource = children; 

    } 

} 

Finalmente, llamé a prepararse para segue el que busca el segue etiquetada SEGUE1.

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if([[segue identifier] isEqualToString:@"segue1"]) 
    { 
     DrillDownDetailController *dvController = [[segue destinationViewController] visibleViewController]; 
     //DrillDownDetailController *dvController = [[DrillDownDetailController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]]; 
     [dvController setItemName:(NSString *)sender]; 
     [self.navigationController pushViewController:dvController animated:YES]; 
    } 
} 

pensé que esto iba a funcionar, pero por alguna razón, cada vez que el código alcanza [self performSegueWithIdentifier:@"segue1" sender:myString];, se rompe con el error

***** Terminación de aplicación debido a excepción no detectada 'NSInvalidArgumentException', por: 'receptor() no tiene segue con identificador 'SEGUE1'' * pila de llamadas primer tiro: (0x14b4022 0xeb4cd6 0xdf61b 0x3590 0xa85c5 0xa87fa 0x93d85d 0x1488936 0x14883d7 0x13eb790 0x13ead84 0x13eac9b 0x139d7d8 0x139d88a 0x17626 0x23ed 0x2355 0x1) por terminado llama lanzar una excepción (LLDB)

No puedo entender por qué me dice que no puede encontrar segue1 cuando ya está definido en el guión gráfico y el código.

+1

Puedo estar COMPLETAMENTE DESACTIVADO aquí, ya que no uso mucho, pero intento declarar 'DrillDownDetailController * dvController' como una variable de instancia y luego en' prepareForSegue' establecer las propiedades que necesite en el VC. No presione el VC al controlador de naval en la preparación y luego realice la búsqueda. – mkral

+0

@mkral ¿podría dar más detalles sobre "No presione el VC al controlador de naval en la preparación y luego realice la búsqueda"? Entonces, ¿quita la línea pushViewController y coloca esa línea en una nueva función performSegue? – foboi1122

+0

Agregaré una respuesta formateada. Si no funciona, con suerte alguien más puede venir, – mkral

Respuesta

23

Un par de problemas, en realidad:

Primera , en ese proyecto que ha cargado para nosotros, el segue hace no llevan el "SEGUE1" identificador:

no identifier

Debe completar ese identificador si aún no lo ha hecho.

Segundo, cuando presiona desde la vista de tabla a la vista de tabla, llama al initWithNibName para crear un controlador de vista. ¿De verdad quieres usar instantiateViewControllerWithIdentifier.

Por lo tanto, la línea que dice:

DrillDownViewController *rvController = [[DrillDownViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]]; 

debería decir:

DrillDownViewController *rvController = [self.storyboard instantiateViewControllerWithIdentifier:@"TableView"]; 

Tercer, su prepareForSegue fue:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if([[segue identifier] isEqualToString:@"segue1"]) 
    { 
     dvController = [[segue destinationViewController] visibleViewController]; 
     [dvController setItemName:self->nameToSend]; 
    } 
} 

Y es que es necesario simplificar para eliminar referencia a visibleViewController, por ejemplo .:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
{ 
    if([[segue identifier] isEqualToString:@"segue1"]) 
    { 
     dvController = segue.destinationViewController; 
     dvController.itemName = nameToSend; 
    } 
} 

Cuarta, su DrillDownDetailController.m tiene este método:

-(void) setItemName:(NSString *)itemName 
{ 
    if(!itemName) 
    { 
     itemName = [[NSString alloc] initWithString:itemName]; 
    } 
    label.text = itemName; 
} 

Hay un montón de problemas aquí, pero que simplemente no debería actualizando el label.text aquí (porque todavía no podría ¡ser creado!). Usted sólo debe eliminar este método de selección personalizada por completo (acaba de dejar Xcode sintetizar el organismo normativo para usted) y acaba de cambiar su viewDidLoad de la siguiente manera:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    label.text = self.itemName; 
} 

Asegúrese de que no se actualizan los objetos de interfaz de usuario hasta viewDidLoad!

No he pasado por todo el programa, pero con esas cuatro correcciones puedo pulsar "SubItem1", luego "Cars", y luego "BMW" y veo una pantalla de detalles que dice "BMW". Creo que hay algunos problemas con su plist en otros elementos (por ejemplo, las entradas de zapatos son cadenas, y no las entradas del diccionario y se obtiene un error ... Supongo que usted no ha completado su plist completamente), pero las correcciones anteriores corregir los problemas de codificación más importantes.

+1

gracias por su aporte! He arreglado mi problema – foboi1122

2

el principal problema es aquí, estuviera creando un DrillDownViewController en blanco, no reutilizar el de guiones gráficos, ver comentarios en código de abajo

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    { 
     if([[segue identifier] isEqualToString:@"segue1"]) 
     { 
      [segue.destinationViewController setItemName:(NSString*)sender]; 
     } 
    } 

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
    { 
     //Check the dictionary to see what cell was clicked 
     NSDictionary *dict = [self.tableDataSource objectAtIndex:indexPath.row]; 
NSString *titleName = [dict objectForKey:@"Title"]; 
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row]; 

NSArray *children = [dictionary objectForKey:@"Children"]; 

if([children count] == 0) 
{ 
    [self performSegueWithIdentifier:@"segue1" sender:titleName]; 

} 
     else{ 
    //Prepare to tableview. 

    //THE MAIN ISSUE IS HERE, you were creating a blank DrillDownViewController, not reusing the one from storyboards so it did not have a segue at all defined. instead do this: 
    UIStoryboard* sb = [UIStoryboard storyboardWithName:@"MainStoryboard" 
                bundle:nil]; 
    DrillDownViewController *rvController = [sb instantiateViewControllerWithIdentifier:@"DDVC"];  
    //Increment the Current View 
    rvController.CurrentLevel += 1; 

    //Set the title; 
    rvController.CurrentTitle = [dictionary objectForKey:@"Title"]; 

    //Push the new table view on the stack 
    [self.navigationController pushViewController:rvController animated:YES]; 

    rvController.tableDataSource = children; 

} 


    } 
+0

puede enviar NSString a través del remitente? O está mal visto. la mayoría de las veces veo remitente: sí, pero no vi ninguna referencia al remitente en el código, así que asumí que podía enviar lo que quisiera como remitente – foboi1122

+0

No estoy seguro de eso, pero no lo hago. Creo que deberías, en su lugar, debes enviar la celda en la que se hizo clic si hay algo, entonces en prepareForSegue obtener la cadena. – mkral

+0

porque en este caso el botón/celda en que se hizo clic ES el remitente. – mkral

Cuestiones relacionadas