CoreData non potrebbe soddisfare un errore per

Ho un fastidioso problema, che io proprio non riesco a ottenere fisso.

Ho vista quando ho inviare un messaggio che viene salvato i Dati di base, quando thats fatto chiesto il database per un messaggio casuale (frase) e salvato che ad un’altra riga nel database.

Se faccio l’ultima parte hardcoded, senza il recupero dei dati dal DB, funziona tutto bene e dandy, ma non appena è possibile recuperare la riga a caso dal DB va pazzo.

Nel mio AppDelegate.m:

- (void)save {
    NSAssert(self.context != nil, @"Not initialized");
    NSError *error = nil;
    BOOL failed = [self.context hasChanges] && ![self.context save:&error];
    NSAssert1(!failed,@"Save failed %@",[error userInfo]);
}

- (NSString*)selectRandomSentence
{
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Sentences" inManagedObjectContext:self.managedObjectContext];
    [request setEntity:entity];

    NSError *error = nil;
    NSUInteger count = [self.context countForFetchRequest:request error:&error];

    NSUInteger offset = count - (arc4random() % count);
    [request setFetchOffset:offset];
    [request setFetchLimit:1];

    NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];

    [request release];

    return [[sentenceArray objectAtIndex:0] sentence];
}

- (NSManagedObjectContext *)context {

    if (_managedObjectContext != nil)
        return _managedObjectContext;

    NSPersistentStoreCoordinator *coordinator = [self coordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }

    return _managedObjectContext;
}

Nel mio ChatController.m:

- (void)didRecieveMessage:(NSString *)message
{
    [self addMessage:message fromMe:NO];
}

#pragma mark -
#pragma mark SendControllerDelegate

- (void)didSendMessage:(NSString*)text {
    [self addMessage:text fromMe:YES];
}

#pragma mark -
#pragma mark Private methods

- (void)responseReceived:(NSString*)response {
    [self addMessage:response fromMe:NO];
}

- (void)addMessage:(NSString*)text fromMe:(BOOL)fromMe {
    NSAssert(self.repository != nil, @"Not initialized");
    Message *msg = [self.repository messageForBuddy:self.buddy];
    msg.text = text;
    msg.fromMe = fromMe;

    if (fromMe)
    {
        [self.bot talkWithBot:text];
    }

    [self.repository asyncSave];

    [self.tableView reloadData];
    [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:[self.buddy.messages count] - 1] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

Nel Mio OfflineBot.m:

- (void)talkWithBot:(NSString *)textFromMe
{
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
    [self didRecieveMessage:[delegate selectRandomSentence]];
}

- (void)didRecieveMessage:(NSString *)message
{
    if ([self.delegate respondsToSelector:@selector(didRecieveMessage:)])
        [self.delegate didRecieveMessage:message];
}

Repository.m

- (Message*)messageForBuddy:(Buddy*)buddy {
    Message *msg = [self.delegate entityForName:@"Message"];
    msg.source = buddy;
    [self.delegate.managedObjectContext refreshObject:buddy mergeChanges:YES];
    return msg;
}

- (void)asyncSave {
    [self.delegate save];
}

L’errore:

2012-08-10 00:28:20.526 Chat[13170:c07] * errore di Asserzione in
-[AppDelegate salva] /Utenti/paulp/Desktop/TestTask/Classi/AppDelegate.m:28 2012-08-10
00:28:20.527 Chat[13170:c07] *
di Terminazione app a causa di uncaught
eccezione ‘NSInternalInconsistencyException’, motivo: ‘impossibile Salvare
{type = immutabile dict, count = 2,
voci => 1 : {indice =
“NSAffectedObjectsErrorKey”} = (
“(entità: Frasi; id: 0x6b8bf10 ;
dati: )” ) 2 : {indice =
“NSUnderlyingException”} = CoreData non potrebbe soddisfare un errore per
‘0x6b8bf10
‘}

Che cosa sto facendo di sbagliato?

Aggiornamento
Ho individuato l’errore a questa riga:

NSArray *sentenceArray = [self.context executeFetchRequest:request error:&error];

Quando provo a eseguire la riga, mi esce l’errore… che è quando il recupero dei dati. L’errore, tuttavia, sembra girare fino a quando il salvataggio di nuovi dati per i Messaggi entità. Il casuale frase viene recuperata dalle Frasi.

Dopo che ho cambiato il asyncSave metodo per il salvataggio direttamente (quindi non utilizzando un nuovo thread) si risparmia la prima chat, ma niente dopo che. Muore.

Aggiornamento
Tutto sembra funzionare utilizzando questo nel mio didFinishLaunchingWithOptions:

[self.context setRetainsRegisteredObjects:YES];

Ho capito che con la presente il CodeData Modello a Oggetti di Contesto non rilasciare gli oggetti, che sembra essere il problema betweens aggiunta e risparmio. Ma perché?

  • Paolo, l’aggiornamento hai detto che hai individuato il tuo errore executeFetchRequest chiamare ancora l’errore si verifica durante il salvataggio del contesto che non ha senso. Qualsiasi possibilità di utilizzare più thread nella vostra applicazione? Molto spesso colpevole per NSInternalInconsistencyException
  • Qual è la differenza tra sé.contesto e di auto.managedObjectContext. Ti sembra di essere li utilizzano come sinonimi, e che non suona come una buona idea.
  • Inoltre, sembra che non si utilizza l’ARCO, ma non guardare come si sta a gestire correttamente la vostra memoria. Questo errore di solito significa che hai cancellato qualcosa dal negozio, ma non aggiornare correttamente il MOC, o hai più thread che pasticciano con la stessa MOC.
  • Auto.il contesto è nulla di più quindi un metodo a mio AppDelegate. Ho analizzato e controllato il mio codice, ma non ho perdite di memoria c’. Come posso garantire io stesso thread?
  • … Ho aggiornato la domanda. Inoltre, per spiegare il mio ultimo commento: non ho nessun tipo di perdite a tutti. Né posso ottenere qualsiasi analizy o messaggi durante la costruzione.
  • cosa @PeterPajchl detto: l’applicazione è multi-threaded? Sei accedere ai vostri Dati essenziali oggetto gestito contesto da più thread? (Uh oh!)
  • Ero prima, ma ho rimosso quella parte. Il asyncsave fatto un preformselector con ritardo 0, che ha ritardato l’salvare in un nuovo thread. Per quanto io so e posso vedere, non sto usando thread.
  • inoltre, invece di arc4random() % count, è possibile utilizzare arc4random_uniform( count ). È più corretto, non che sia importante.
  • Prima di accedere aggiungere questo: assert( [ NSThread currentThread ] == [ NSThread mainThread ] )
  • .. Ok, che devo fare, che sia durante la lettura e il salvataggio? Se non è la stessa gettato un’eccezione nel registro… dico bene?
  • inoltre, si dispone di un OBOB (disattivato da un bug) credo: (conte – arc4random() % count) può essere uno di alta. Utilizzare count - 1 - arc4random() % count
  • sì, non sono sul thread principale in crash… È possibile utilizzare NSAssert() per generare un’eccezione invece..
  • Ok. Mi darà una prova in un po’. Se non sono sul thread principale, come posso essere sicuro che mi sarà? Naturalmente, a parte la rimozione di preformeSelector ect.
  • cerchiamo di continuare questa discussione in chat

InformationsquelleAutor Paul Peelen | 2012-08-09



5 Replies
  1. 6

    Non è proprio concettualmente possibile “salvare” Dati principali “oggettiin righe diverse“. Ricordate, Core Data è un oggetto grafico e non un database.

    Se si vuole “spostare” la tua frase, il modo migliore è quello di distruggere e ricreare. Se si desidera mantenere il vecchio esempio, di crearne uno nuovo e poi completa la proprietà da quella esistente.

    Per distruggere, utilizzare

    [self.context deleteObject:sentenceObject];

    Per ricreare, utilizzare

    Sentence *newSentence = [NSEntityDescription insertNewObjectForEntityForName:
      "Sentences" inManagedObjectContext:self.context];
    newSentence.sentence = sentenceObject.sentence;
    //fill in other properties, then
    [self.context save:error];

    Se desideri leggere su questo, guardare “Copia e Copia e Incolla” nella sezione “Utilizzo di Oggetti Gestiti” della sezione “Dati di base Manuale di Programmazione”.

  2. 62

    Hmm. Sei la corretta attuazione di concorrenza seguenti questa guida?
    Il problema che si sta vedendo è un comune utilizzo di core di dati tra più thread. L’oggetto è stato eliminato nel “contesto”, mentre poi si accede da un altro contesto. Chiamata [context processPendingChanges] sul contesto di fondo dopo l’eliminazione, ma prima del salvataggio può essere di aiuto.

    C’è anche un WWDC 2010 sessione (137) sull’ottimizzazione dei dati essenziali delle prestazioni che va in elimina un po’.

    Quando si esegue un’operazione di recupero di Dati di base restituisce una collezione di oggetti di corrispondenza il predicato è fornito. Quegli oggetti che in realtà non hanno i loro valori di proprietà ancora. Quando si accede a una proprietà che i Dati di Nucleo risale al negozio di “fuoco colpa” – compilare la proprietà con i dati del negozio. “Non potrebbe soddisfare una colpa…” eccezioni accadere quando i Dati di base va al negozio per ottenere i valori delle proprietà di un oggetto, ma l’oggetto non esiste in un archivio permanente. L’oggetto gestito contesto pensiero dovrebbe esistere, che è il motivo per cui si può tentare la colpa – che è dove è il problema. Il contesto che ha causato l’eccezione di non sapere che questo oggetto è stato eliminato dallo store da qualcos’altro (come un altro contesto).

    Nota di cui sopra la Concorrenza di Guida aggiornato, deve essere utilizzato il genitore-bambino contesti e privato coda di concorrenza, piuttosto che il vecchio thread di confinamento modello. Padre-figlio contesti sono molto meno probabilità di incorrere in “non Potrebbe soddisfare una colpa…” per molti motivi. E, per favore, file di un bug di documentazione o utilizzare il modulo di contatto per richiedere la concorrenza di guida per essere aggiornati.

    • +1 penso che questa risposta effettivamente risolve il problema tecnico in questione in OP problema
    • re il link alla guida: “Importante: le Migliori pratiche per la concorrenza con i Dati principali sono cambiate drasticamente dopo questo documento è stato scritto; si prega di notare che questo capitolo non rappresentano attuali raccomandazioni.”
    • si prega di leggere la mia risposta alla fine.
    • oh! mi dispiace! Se non oggetto, vado a cancellare il mio commento(s) nell’interesse di mantenere questo comune in ordine (e non mi sembrano abbastanza stupido come io in realtà sono).
  3. 1

    controllare i dati di base meccanismo. “L’errore di ridurre la quantità di memoria applicazione consuma. Un errore è un segnaposto che rappresenta un oggetto gestito che non si è ancora pienamente realizzato, o un oggetto da collezione che rappresenta una relazione:”

    • Si potrebbe citare il preventivo?
    • in Dati di base Manuale di Programmazione, e di ricerca con “CoreData non potrebbe soddisfare un errore” nel documento, l’unità “meccanismo di Errore”
    • “Sparare un errore” significa di Dati di base che deve andare in archivio permanente per popolare un oggetto gestito valore della proprietà. L’accesso a una proprietà che è un errore fare questo. “Non poteva compiere un errore” significa che è andato al negozio, ma non ci sono dati per questo oggetto, di solito a causa di qualcosa eliminato il record.
    • Grazie per questo, io a volte vedo questo errore e non capiva perché. Questo succede quando mi registro l’oggetto intero, ma ho ancora in grado di accedere ai singoli campi.
  4. 0

    Questo accade perché si è aggiunto il “messaggio casuale” per la nuova riga prima del completamento del recupero di tutte le tue relazioni della prima chiamata.

    È possibile aggiungere un prefetch per il 1 ° appello ad evitare il caricamento lazy e il problema sarà risolto, credo.

    Questo è come si può fare prelettura per la richiesta:

    [request setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects:@"whatEverOfYourWillNumberOne",@"whatEverOfYourWillNumberTwo", nil]];

    Speranza che aiuta.

  5. 0

    Ho corretto l’errore con la modifica NSFetchedResultsController del “cacheName” stringa di zero.

    NSFetchedResultsController *aFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
    managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
    cacheName:@”Root”nil];

Lascia un commento