1

Dans mon application, j'obtiens des requêtes avec du contenu JSON, les analyse et les stocke dans CoreData. En même temps, l'utilisateur interagit avec le DB (accès en lecture et en écriture). Après le stockage des données dans le DB, une seconde tâche est lancée pour créer de nouvelles données, en fonction des données reçues. Je vais utiliser Grand Central Dispatch pour effectuer l'analyse et stocker les données dans la base de données. Mon problème est que lorsque j'utilise GCD, j'obtiens un EXC_BAD_ACCESS, ce qui pourrait être dû à la sécurité non-thread des Core Data que je suppose. Une autre erreur est que je reçois un blocage en utilisant le contexte performBlockAndWait. Comment concevoir mon application qui gère correctement GCD et NSMutableContexts?Conception d'une application iOS avec plusieurs accès DB parallèles

------- -------- EDIT

Maintenant que j'ai lu le guide de programmation de données de base I cam au point que je dois utiliser le modèle de Confinement de fil.

Mon application est actuellement structurée de la façon suivante: j'ai deux gestionnaires qui ont chacun leur propre contexte. Mais lorsque j'utilise plusieurs threads, j'en arrive au point où 3 threads appellent le même gestionnaire, ce qui signifie qu'un contexte est utilisé par 3 threads simultanément. Cela entraîne une impasse.

Pour résoudre ce je suis venu à l'idée de créer un contexte par ThreadName comme ceci:

- (NSManagedObjectContext *)createManagedObjectContextWithTreadName:(NSString*) threadname { 

    if([NSThread currentThread].name.length ==0){ 
     [NSThread currentThread].name = threadname; 
    } 

    NSManagedObjectContext *context = nil; 
    context = [self.contextStore objectForKey:threadname]; 

    if(!context){ 
     NSLog(@"Creating context for threadname: %@",threadname); 

     NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator; 
     if (coordinator != nil) 
     { 
      context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
      context.persistentStoreCoordinator = coordinator; 
      context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy; 

      NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
      [nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:context]; 
      [self.contextStore setValue:context forKey:threadname]; 
     } 
    } 
    return context; 
} 

Est-ce une bonne idée?

Répondre

2

Ok - voici comment je l'ai résolu:

+(NSManagedObjectContext *)managedObjectContext { 
    AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate; 
    NSManagedObjectContext *moc = delegate.managedObjectContext; 

    NSThread *thread = [NSThread currentThread]; 

    if ([thread isMainThread]) { 
     return moc; 
    } 

    // a key to cache the context for the given thread 
    NSString *threadKey = [NSString stringWithFormat:@"%p", thread]; 

    // delegate.managedObjectContexts is a mutable dictionary in the app delegate 
    NSMutableDictionary *managedObjectContexts = delegate.managedObjectContexts; 

    if ([managedObjectContexts objectForKey:threadKey] == nil) { 
     // create a context for this thread 
     NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 

     threadContext.persistentStoreCoordinator = [moc persistentStoreCoordinator]; 
     threadContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy; 

     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
     [nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:threadContext]; 

     // cache the context for this thread 
     [managedObjectContexts setObject:threadContext forKey:threadKey]; 
     //NSLog(@"MocCount: %d",managedObjectContexts.count); 
    } 

    return [managedObjectContexts objectForKey:threadKey]; 
} 

+ (void)mergeChangesFromMOC:(NSNotification *)aNotification { 

    //NSLog(@"Performing a merge of managed object context in class %@",[self class]); 

    @try { 
     AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate; 
     NSManagedObjectContext *moc = delegate.managedObjectContext; 
     [moc mergeChangesFromContextDidSaveNotification:aNotification]; 


     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
     [nc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:[aNotification object]];  
    } 
    @catch (NSException * e) { 
     NSLog(@"Stopping on exception: %@", [e description]); 
    } 
    @finally {} 
} 

Partout je besoin d'un contexte, je demande [ContainingClass managedObjectContext] et obtenir le contexte pour le thread principal ou le fil que je suis quand une fusion. est nécessaire cela est effectué sur le thread principal.

+0

wow ... je vous aime pour ce poste. impressionnant ! – yunas

+0

Juste une question, comment supprimez-vous les contextes pour les threads qui ne sont plus en vie? –

Questions connexes