2009-07-02 19 views
8

Escribo mi primera aplicación iPhone/Cocoa. Tiene dos vistas de tabla dentro de una vista de navegación. Cuando toca una fila en la primera vista de tabla, se le lleva a la segunda vista de tabla. Me gustaría que la segunda vista muestre registros de las entidades de CoreData relacionadas con la fila que tocó en la primera vista.Pasar un ManagedObjectContext a una segunda vista

Tengo los datos de CoreData apareciendo bien en la primera vista de tabla. Puede tocar una fila y acceder a la segunda vista de tabla. Puedo pasar información del objeto seleccionado de la primera a la segunda vista. Pero no puedo obtener la segunda vista para hacer su propia búsqueda de CoreData. Por mi vida, no puedo hacer que el objeto managedObjectContext pase al segundo controlador de vista. No quiero hacer las búsquedas en la primera vista y aprobar un diccionario porque quiero poder usar un campo de búsqueda para refinar los resultados en la segunda vista, así como insertar nuevas entradas a los datos de CoreData desde allí.

Aquí está la función que realiza la transición de la primera a la segunda vista.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    // Navigation logic may go here -- for example, create and push another view controller. 
    NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath]; 
    SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondView" bundle:nil]; 

    secondViewController.tName = [[selectedObject valueForKey:@"name"] description]; 
    secondViewController.managedObjectContext = [self managedObjectContext]; 

    [self.navigationController pushViewController:secondViewController animated:YES]; 
    [secondViewController release]; 
} 

Y esta es la función dentro SecondViewController que se estrella:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.title = tName; 

    NSError *error; 
    if (![[self fetchedResultsController] performFetch:&error]) { // <-- crashes here 
     // Handle the error... 
    } 
} 

- (NSFetchedResultsController *)fetchedResultsController { 

    if (fetchedResultsController != nil) { 
     return fetchedResultsController; 
    } 

    /* 
    Set up the fetched results controller.  
    */ 
    // Create the fetch request for the entity. 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    // Edit the entity name as appropriate. 
     // **** crashes on the next line because managedObjectContext == 0x0 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    // <snip> ... more code here from Apple template, never gets executed because of the crashing 

    return fetchedResultsController; 
} 

¿Alguna idea de lo que estoy haciendo mal aquí?

managedObjectContext es una propiedad retenida.

ACTUALIZACIÓN: inserté una descripción de NSLog ([[managedObjectContext registeredObjects]]); en viewDidLoad y parece que managedObjectContext se está pasando muy bien. Sin embargo, sigue estrellándose.

Terminación de aplicación debido a excepción no detectada 'NSInternalInconsistencyException', razón: '+ entityForName: no se pudo localizar un NSManagedObjectModel a nombre de la entidad 'SecondEntity''

+0

¿Qué sucede cuando coloca el código que inicializa el controlador de resultados obtenidos en viewDidLoad? Tengo una aplicación que hace esencialmente lo mismo, y funciona bien para mí, pero creo mi controlador de resultados obtenidos directamente en viewDidLoad con initWithFetchRequest: managedObjectContext: sectionNameKeyPath: cacheName :. – Tim

+0

@Tim Acabo de intentarlo, se bloquea de la misma manera. Lo extraño es que si establezco un punto de interrupción, todas las variables miembro de self son NULL, pero el título se establece correctamente, por lo que no puede ser cierto. – amo

Respuesta

7

Oh, esto es interesante. Pasé un tiempo de calidad con el trazado de pila y creo que lo tengo resuelto.

Así que pushViewController llama a viewDidLoad no una vez, pero dos veces.La primera vez que llama a viewDidLoad, parece que los objetos no se crean correctamente. La segunda vez, lo son. Por lo tanto, la primera vez que se ejecuta este código no puede acceder a managedObjectContext y arroja una excepción. La segunda vez que se ejecuta, todo está bien. Sin accidente.

Hay muchas referencias a problemas con la ejecución de viewDidLoad varias veces en Google, por lo que creo que la solución es no hacer esta inicialización de solicitud de recuperación en viewDidLoad.

+0

¿Qué pasa con viewDidAppear? – film42

0

¿Estás seguro de que hay una entidad llamada "SecondEntity"? (Esa sería la forma directa de interpretar el mensaje de error.)

Sin embargo, si esta es una lista maestra -> vista de detalle tipo interacción, sugeriría pasar el objeto seleccionado directamente al segundo controlador de vista, en lugar de dar solo el "nombre". Presumiblemente, este objeto contiene todo lo que necesita para completar la segunda tabla directamente a través de sus propiedades.

De esta forma, no realiza ninguna búsqueda explícita en el segundo controlador de vista. Es decir:

@interface SecondViewController : UITableViewController 
@property (nonatomic, retain) NSManagedObject *selectedObject; 
@end 

@implementation SecondViewController 
- (void)viewDidLoad 
{ 
    NSMutableArray *stuff = [[[selectedObject valueForKey:@"aToManyRelationship"] allObjects] mutableCopy]; 
    // sort stuff the way you want to display them, etc. 
} 
... 
+0

Sí, la entidad existe. No es la lista maestra-> detalle ... es más como categoría-> elementos, y quiero poder interactuar directamente con el almacén de datos, porque la segunda vista es realmente la pantalla de interacción principal, por lo que no quiero simplemente pasar una instantánea a la segunda vista. – amo

0

Sólo por diversión .. intente reemplazar:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:managedObjectContext]; 

con:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:[self managedObjectContext]]; 

Usted está configurando managedObjectContext a través de un organismo, y luego tratar de acceder al Ivar directamente. Dependiendo de cómo se definan sus propiedades, esto puede no ser correcto. [self managedObjectContext] intentará acceder al valor a través del getter, en lugar de directamente.

+0

Interesante. Intentaré esto cuando llegue a casa. – amo

+0

¿Significa eso que self.title = tName también es mala forma? – amo

+1

No, en absoluto. Aunque no estoy seguro de dónde viene tName. la sintaxis de punto en Objective C * está * llamando a sus métodos de acceso, aunque puede * aparecer * golpear ivars. – mmc

1

He estado luchando con el mismo problema y todavía soy un novato. Creo que descubrí lo que está pasando. Avísame si esto tiene sentido.

En resumen, está tratando de recuperar una entidad de un objectContext que aún no se ha configurado. Por lo tanto, sus opciones son configurarlo en ese momento o hacerlo en otra parte de la aplicación antes de que se cargue esta vista.

Si la aplicación está configurada como la aplicación de demostración CoreDataBooks del centro de desarrollo de iPhone con un UIApplicationDelegate principal también la gestión de la pila CoreData, entonces debería ser capaz de hacer lo siguiente:

if (managedObjectContext == nil) { managedObjectContext = [[[UIApplication sharedApplication] delegate] managedObjectContext]; }

Esto debería Haz el truco.

-2

Una cosa es cierta, la línea: secondViewController.managedObjectContext = [self managedObjectContext];

Debe ser: secondViewController.managedObjectContext = self.managedObjectContext;

A menos que el objeto actual implemente un método llamado 'managedObjectContext' que devuelve esa variable.

-1

Este podría ser el problema.

respuesta corta: borre su aplicación y vuelva a ejecutarla.

respuesta larga:

Si crear y ejecutar el proyecto, CoreData ahorrará su modelo a donde quiera que usted dijo a (lugar de almacenamiento persistente).

Si cambia algo en el modelo CoreData, cuando vuelva a ejecutar la aplicación, el nuevo modelo no coincidirá con el modelo guardado que le da ese error.

Para solucionarlo, elimine su aplicación. Esto eliminará el modelo guardado y cuando lo ejecute nuevamente, recreará su nuevo modelo.

18

puede suprimir el '-managedObjectContext' no se encuentra en alerta protocolos mediante la emisión de su delegado primera aplicación:

if (managedObjectContext == nil) { managedObjectContext = [(MyAppDelegateName *)[[UIApplication sharedApplication] delegate] managedObjectContext]; } 
0

he tenido este problema y encontró que el mensaje de inicio de mi objeto era el acceso a la managedObjectContext antes de la setManagedObjectContext era ser llamado ...

Antes:

dataController = [[DataController alloc] init]; 
[dataController setManagedObjectContext:[self managedObjectContext]]; 

Después:

dataController = [DataController alloc]; 
[dataController setManagedObjectContext:[self managedObjectContext]];    
[dataController init]; 

feh. Error de novato

0

Apple proporciona un proyecto de muestra llamado "iPhoneCoreDataRecipes". Hay un artículo muy interesante acerca de pasar NSManagedObjectContext here Si intenta poner en práctica este tipo de lógica que cada managedObjectContext es como una isla por sí misma en cada UIViewController

Trate código

if (managedObjectContext == nil) { managedObjectContext = [(MyAppDelegateName *)[[UIApplication sharedApplication] delegate] managedObjectContext]; } 

Cambio Con esta

if (managedObjectContext == nil) { managedObjectContext = self.managedObjectContext } 
1

en su primera tableViewController, puede pasar el managedObjectContext por: secondTableController.managedObjectContext = [(AppDelegate *) [[UIApplication sharedApplication ] delegate ] managedObjectContext ], tal vez está bien

Cuestiones relacionadas