CoreData ne pouvait pas répondre à une faute pour

J'ai vraiment un problème gênant, que je juste ne pouvez pas sembler obtenir fixe.

J'ai vue quand j'envoie un message est enregistré sur la Base de Données, lorsque c'est fait, il a demandé à la base de données pour un message aléatoire (phrase) et est enregistré aussi bien à une autre ligne dans la base de données.

Si je fais la dernière partie codée en dur, sans extraction de données à partir de la DB, il travaille tous très bien et dandy, mais dès que je récupère la ligne aléatoire à partir de la DB, il devient fou.

Dans mon 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;
}

Dans mon 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];
}

Dans Mon 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];
}

Référentiel.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'erreur:

2012-08-10 00:28:20.526 Chat[13170:c07] * échec d'Assertion dans
-[AppDelegate enregistrer], /Users/paulp/Desktop/TestTask/Classes/AppDelegate.m:28 2012-08-10
00:28:20.527 Chat[13170:c07] *
Résiliation d'application en raison de uncaught
exception NSInternalInconsistencyException', la raison: "Enregistrer échoué
{type = immuable dict, count = 2,
entrées => 1 : {contenu =
"NSAffectedObjectsErrorKey"} = (
"(entité: Phrases; id: 0x6b8bf10 ;
données: )" ) 2 : {contenu =
"NSUnderlyingException"} = CoreData ne pouvait pas répondre à une faute pour
'0x6b8bf10
'}

Ce que je fais mal?

Mise à jour
J'ai pointé l'erreur à cette ligne:

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

Lorsque j'exécute la ligne, j'obtiens l'erreur... c'est lors de l'extraction de données. L'erreur, cependant, semble tourner lors de l'enregistrement de nouvelles données pour les Messages de l'entité. Le hasard phrase est extraite à partir des Phrases.

Après j'ai changé le asyncSave méthode pour l'enregistrement direct (donc pas à l'aide d'un nouveau thread), il enregistre le premier chat, mais rien après. Il meurt.

Mise à jour
Tout semble fonctionner à l'aide de ce dans mon didFinishLaunchingWithOptions:

[self.context setRetainsRegisteredObjects:YES];

Je comprends que, par la présente, le CodeData Modèle d'Objet de Contexte n'a pas communiqué ses objets, ce qui semble être le problème entre l'ajout et de l'épargne. Mais pourquoi?

  • Paul, dans votre mise à jour vous mentionner que vous avez identifié votre erreur executeFetchRequest appel encore votre erreur survient lors de l'enregistrement de votre contexte qui n'a pas de sens. Aucune chance de l'utilisation de plusieurs threads dans votre application? C'est très souvent coupable pour NSInternalInconsistencyException
  • Quelle est la différence entre le soi.contexte et l'auto.managedObjectContext. Vous semblez être les utiliser de façon interchangeable, et qui ne sonne pas comme une bonne idée.
  • Aussi, il semble que vous n'êtes pas à l'aide de l'ARC, mais il ne semble pas que vous êtes la bonne gestion de votre mémoire. Cette erreur signifie généralement que vous avez supprimé quelque chose de la boutique, mais ne s'est pas correctement mise à jour de votre MOC, ou vous avez plusieurs threads de jouer avec le même MOC.
  • Auto.le contexte n'est rien de plus qu'une méthode dans ma AppDelegate. J'ai analysé et vérifié mon code, mais je n'ai pas de fuites de mémoire là. Comment puis-je m'assurer que je suis sur le même thread?
  • ... J'ai mis à jour la question. Aussi, pour expliquer mon dernier commentaire: je n'ai pas de fuites à tous. Ni puis-je obtenir toute analizy ou des avertissements lors de la construction.
  • ce que @PeterPajchl dit: est-ce votre application multi-thread? Êtes-vous accéder à votre Base de Données gérée contexte de l'objet à partir de plusieurs threads? (Oh oh!)
  • J'étais avant, mais j'ai supprimé cette partie. Le asyncsave fait un preformselector avec un délai de 0, ce qui a retardé l'enregistrer dans un nouveau thread. Autant que je sache, et peut le voir, je ne suis pas à l'aide de threads.
  • aussi, au lieu de arc4random() % count, vous pouvez utiliser arc4random_uniform( count ). Il est plus correct, non pas que cela importe.
  • Avant votre accès ajouter ceci: assert( [ NSThread currentThread ] == [ NSThread mainThread ] )
  • .. Ok, je devrais le faire à la fois lors de la lecture et de l'économie? Si ce n'est pas le même, il sera jeté une exception dans le journal... suis-je le droit?
  • aussi, vous avez un OBOB (désactivé par un bug) je crois: (comte - arc4random() % nombre) peut être l'un de haut. Utilisation count - 1 - arc4random() % count
  • oui--non pas sur le thread principal va s'écraser... Vous pouvez utiliser NSAssert() lève une exception à la place..
  • Ok. Je vais essayer un peu. Si je ne suis pas sur le thread principal, comment puis-je m'assurer que je serai? Bien sûr, une partie de la suppression de preformeSelector ect.
  • laissez-nous continuer cette discussion dans le chat

InformationsquelleAutor Paul Peelen | 2012-08-09