2009-07-02 13 views
8

Sto scrivendo la mia prima app per iPhone/Cocoa. Ha due viste tabella all'interno di una vista di navigazione. Quando si tocca una riga nella prima vista tabella, si passa alla seconda vista tabella. Vorrei che la seconda vista visualizzasse i record delle entità CoreData relative alla riga che hai toccato nella prima vista.Passaggio di ManagedObjectContext a una seconda vista

Ho i dati di CoreData che mostrano bene nella prima vista tabella. Puoi toccare una riga e andare alla seconda vista tabella. Sono in grado di passare informazioni dall'oggetto selezionato dalla prima alla seconda vista. Ma non riesco a ottenere la seconda vista per fare il proprio recupero CoreData. Per la vita di me non riesco a far passare l'oggetto managedObjectContext al secondo controller di visualizzazione. Non voglio fare le ricerche nella prima vista e passare un dizionario perché voglio essere in grado di usare un campo di ricerca per affinare i risultati nella seconda vista, così come inserire nuove voci nei dati CoreData da lì.

Ecco la funzione che passa dalla prima alla seconda 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]; 
} 

E questa è la funzione all'interno SecondViewController che si blocca:

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

Tutte le idee su quello che sto facendo male qui?

managedObjectContext è una proprietà mantenuta.

UPDATE: Ho inserito un NSLog ([[objectObjectContext registeredObjects] description]); in viewDidLoad e sembra che managedObjectContext sia passato bene. Ancora in crash, però.

terminazione app a causa di eccezione non identificata 'NSInternalInconsistencyException', la ragione: '+ entityForName: impossibile individuare un NSManagedObjectModel per nome dell'entità 'SecondEntity''

+0

Cosa succede quando si inserisce il codice che inizializza il controller dei risultati recuperati in viewDidLoad? Ho un'app che fa essenzialmente la stessa cosa, e funziona bene per me, ma creo il mio controller dei risultati recuperato direttamente in viewDidLoad con initWithFetchRequest: managedObjectContext: sectionNameKeyPath: cacheName :. – Tim

+0

@Tim L'ho appena provato, si blocca nello stesso modo. La cosa strana è che se imposto un breakpoint, tutte le variabili membro di self sono NULL, ma il titolo viene impostato correttamente in modo che non possa essere vero. – amo

risposta

7

Oh, questo è interessante. Ho trascorso un po 'di tempo con la traccia dello stack e penso di aver capito.

Quindi pushViewController chiama viewDidLoad non una volta, ma due volte.La prima volta che chiama viewDidLoad, gli oggetti sembrano non essere istanziati correttamente. La seconda volta, lo sono. Quindi, la prima volta che viene eseguito questo codice non può accedere a managedObjectContext e genera un'eccezione. La seconda volta che funziona, va tutto bene. Nessun incidente.

Ci sono molti riferimenti a problemi con viewDidLoad che si esegue più volte su Google, quindi penso che la soluzione non sia l'inizializzazione della richiesta di recupero in viewDidLoad.

+0

Che dire di viewDidAppear? – film42

0

Sei sicuro che c'è un'entità chiamata "SecondEntity"? (Questo sarebbe il modo semplice per interpretare il messaggio di errore.)

Tuttavia, se questo è un elenco principale -> interazione tipo vista di dettaglio, suggerirei di passare l'oggetto selezionato direttamente al secondo controller di visualizzazione, piuttosto che dare è solo il "tname". Questo oggetto contiene presumibilmente tutto ciò che è necessario per popolare la seconda tabella direttamente tramite le sue proprietà.

In questo modo, non si esegue alcun prelievo esplicito nel secondo controller della vista. Cioè:

@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ì, l'entità esiste. Non è la lista master-> dettaglio .. è più come categoria-> elementi, e voglio essere in grado di interagire direttamente con l'archivio dati, perché la seconda vista è in realtà la schermata di interazione principale, quindi non voglio per passare semplicemente un'istantanea alla seconda vista. – amo

0

Solo per i calci .. provare a sostituire:

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

con:

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

Si sta impostando managedObjectContext attraverso un setter, e poi cercando di accedere direttamente alla ivar. A seconda di come sono definite le proprietà, questo potrebbe non essere corretto. [self managedObjectContext] proverà ad accedere al valore attraverso il getter, piuttosto che direttamente.

+0

Interessante. Proverò questo quando torno a casa. – amo

+0

Significa che self.title = tName è anche una cattiva forma? – amo

+1

Niente affatto. Anche se non sono sicuro di dove tName provenga. la sintassi del punto nell'obiettivo C * * sta chiamando i metodi di accesso, anche se * potrebbe * apparire colpendo ivars. – mmc

1

Ho lottato con lo stesso problema e sono ancora solo un principiante. Penso di aver capito cosa sta succedendo. Fammi sapere se questo ha un senso.

In breve si sta tentando di recuperare un'entità da un objectContext che non è stato ancora impostato. Pertanto, le opzioni devono essere configurate subito o eseguite altrove nell'app prima del caricamento di questa vista.

Se la vostra applicazione è configurato come il CoreDataBooks applicazione demo dal centro iPhone Dev con un UIApplicationDelegate principale anche la gestione dello stack CoreData, allora si dovrebbe essere in grado di effettuare le seguenti operazioni:

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

Questo dovrebbe fare il trucco.

-2

Una cosa è certa, la linea: secondViewController.managedObjectContext = [self managedObjectContext];

Dovrebbe essere: secondViewController.managedObjectContext = self.managedObjectContext;

A meno che l'oggetto corrente non implementi un metodo chiamato "managedObjectContext" che restituisce tale variabile.

-1

Questo potrebbe essere il problema.

risposta breve: elimina la tua app, quindi eseguila di nuovo.

risposta lunga:

Se si costruire e gestire il progetto, CoreData salverà il vostro modello ovunque hai detto (persistente percorso di archiviazione).

Se si modifica qualcosa nel modello CoreData, quando si esegue nuovamente l'applicazione, il nuovo modello non corrisponderà al modello salvato dandovi quell'errore.

Per risolvere il problema, elimina la tua app. Questo eliminerà il modello salvato e quando lo riavvierai, ricrea il tuo nuovo modello.

18

È possibile sopprimere il '-managedObjectContext' non trovato in allarme protocolli lanciando il delegato prima applicazione:

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

Ho avuto questo problema e ha scoperto che il messaggio di init di mio oggetto stava accedendo alla managedObjectContext prima della setManagedObjectContext era essere chiamato ...

Prima:

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

Dopo:

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

feh. Errore Rookie.

0

Apple fornisce un progetto di esempio denominato "iPhoneCoreDataRecipes". C'è un articolo molto interessante su passaggio NSManagedObjectContext here Se si tenta di implementare questo tipo di logica che ogni managedObjectContext è come un'isola da solo in ogni UIViewController

Prova codice

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

Modifica Con questa

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

nel tuo primo tableViewController, è possibile passare l'managedObjectContext da: secondTableController.managedObjectContext = [(AppDelegate *) [[UIApplication sharedApplication ] delegate ] managedObjectContext ], forse è ok

Problemi correlati