[RestKit 0.20] Update d'un objet stocké dans CoreData

tplessistplessis Membre
janvier 2013 modifié dans Objective-C, Swift, C, C++ #1
Bonjour,



J'utilise RestKit pour mapper mes objets entre mon webservice REST et mon appli iOs. Je met en cache mes données dans une base sqlite via la couche CoreData. Tout fonctionne lors de la création de mon utilisateur, idem pour l'identification. Vient ensuite le moment de mettre à  jour le compte de l'utilisateur et là , impossible de mettre a jour les données dans CoreData, rien ne se passe.... en revanche aucun probleme côté serveur, les données sont bien envoyées et mises à  jour.



En gros la synchro ne se fait pas côté client, dans la couche CoreData.



Voici mon objet BUser :


<br />
@interface BUser : NSManagedObject<br />
@property (nonatomic, retain) NSNumber *userID;<br />
@property (nonatomic, retain) NSString *name;<br />
@property (nonatomic, retain) NSString *address;<br />
@property (nonatomic, retain) NSString *password;<br />
@property (nonatomic, retain) NSString *token;<br />
@property (nonatomic, retain) NSString *phone;<br />
@property (nonatomic, retain) NSString *email;<br />
@property BOOL *isActivated;<br />
@property BOOL *hasContactsRights;<br />
@property (nonatomic, retain) NSString *city;<br />
@property (nonatomic, retain) NSString *activationCode;<br />
+ (BUser*) sharedInstance;<br />
@end<br />
<br />
@implementation BUser<br />
@synthesize userID;<br />
@synthesize name;<br />
@synthesize address;<br />
@synthesize password;<br />
@synthesize token;<br />
@synthesize phone;<br />
@synthesize email;<br />
@synthesize isActivated;<br />
@synthesize hasContactsRights;<br />
@synthesize city;<br />
@synthesize activationCode;<br />
+ (BUser*) sharedInstance {<br />
	static BUser *myInstance = nil;<br />
	if (myInstance == nil) {<br />
		myInstance = [[[self class] alloc] init];<br />
	}<br />
	return myInstance;<br />
}<br />
@end<br />




Et voici comment j'envoi mon objet BUser via RestKit :


<br />
RKManagedObjectRequestOperation *operation = [[RKObjectManager sharedManager] appropriateObjectRequestOperationWithObject:[BUser sharedInstance] method:RKRequestMethodPUT path:[NSString stringWithFormat:@&quot;/user/%@&quot;, [BUser sharedInstance].userID] parameters:authParams];<br />
		operation.targetObject = [BUser sharedInstance];<br />
		operation.managedObjectContext = [RKObjectManager sharedManager].managedObjectStore.mainQueueManagedObjectContext;<br />
		operation.managedObjectCache = [RKObjectManager sharedManager].managedObjectStore.managedObjectCache;<br />
		[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {<br />
			BUser *user = [result firstObject];<br />
			NSLog(@&quot;Mapped the article: %@&quot;, user);<br />
		} failure:^(RKObjectRequestOperation *operation, NSError *error) {<br />
			NSLog(@&quot;Failed with error: %@&quot;, [error localizedDescription]);<br />
		}];<br />
		NSOperationQueue *operationQueue = [NSOperationQueue new];<br />
		[operationQueue addOperation:operation];<br />




Et pour finir, l'initialisation de RestKit et le mapping que j'utilise :


<br />
// Configure core data to works with RESTkit<br />
	NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];<br />
	RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];<br />
	NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:BAOBAB_DB_NAME];<br />
	[managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:nil];<br />
	[managedObjectStore createManagedObjectContexts];<br />
	RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:REST_SERVER_URL]];<br />
	manager.managedObjectStore = managedObjectStore;<br />
	[managedObjectStore.persistentStoreManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];<br />
	//managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];<br />
  <br />
	// Object Mapping<br />
	RKObjectMapping *userRequestMapping = [RKObjectMapping requestMapping];<br />
	[userRequestMapping addAttributeMappingsFromDictionary:@{<br />
	 @&quot;userID&quot; : @&quot;id&quot;,<br />
	 @&quot;name&quot; : @&quot;name&quot;,<br />
	 @&quot;phone&quot; : @&quot;phone&quot;,<br />
	 @&quot;email&quot; : @&quot;email&quot;,<br />
	 @&quot;city&quot; : @&quot;city&quot;,<br />
	 @&quot;address&quot; : @&quot;address&quot;,<br />
	 @&quot;password&quot; : @&quot;password&quot;<br />
	 }];<br />
	RKEntityMapping* userResponseMapping = [RKEntityMapping mappingForEntityForName:@&quot;BUser&quot; inManagedObjectStore:manager.managedObjectStore];<br />
	[userResponseMapping addAttributeMappingsFromDictionary:@{<br />
	 @&quot;id&quot; : @&quot;userID&quot;,<br />
	 @&quot;name&quot; : @&quot;name&quot;,<br />
	 @&quot;address&quot; : @&quot;address&quot;,<br />
	 @&quot;password&quot; : @&quot;password&quot;,<br />
	 @&quot;phone&quot; : @&quot;phone&quot;,<br />
	 @&quot;email&quot; : @&quot;email&quot;,<br />
	 @&quot;token&quot; : @&quot;token&quot;,<br />
	 @&quot;is_activated&quot; : @&quot;isActivated&quot;,<br />
	 @&quot;has_contacts_rights&quot; : @&quot;hasContactsRights&quot;,<br />
	 @&quot;city&quot; : @&quot;city&quot;,<br />
	 @&quot;activation_code&quot; : @&quot;activationCode&quot;<br />
	 }];<br />
	userResponseMapping.identificationAttributes = @[@&quot;userID&quot;];<br />
	NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx<br />
  <br />
	RKRequestDescriptor *userRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userRequestMapping objectClass:[BUser class] rootKeyPath:@&quot;user&quot;];<br />
	RKResponseDescriptor *userResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userResponseMapping pathPattern:@&quot;/user&quot; keyPath:nil statusCodes:statusCodes];<br />
	RKResponseDescriptor *userLoadResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userResponseMapping pathPattern:@&quot;/user/:userID&quot; keyPath:nil statusCodes:statusCodes];<br />
  <br />
	// Mapping errors<br />
	NSIndexSet *statusCodesErrors = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError);<br />
	RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];<br />
	[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@&quot;errorMessage&quot;]];<br />
	RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping pathPattern:nil keyPath:@&quot;errors&quot; statusCodes:statusCodesErrors];<br />
  <br />
	[manager addRequestDescriptor:userRequestDescriptor];<br />
	[manager addResponseDescriptor:userResponseDescriptor];<br />
	[manager addResponseDescriptor:userLoadResponseDescriptor];<br />
	[manager addResponseDescriptor:errorDescriptor];<br />




Je pense qu'il s'agit peut etre d'un probleme avec le managedContext de CoreData qui n'est plus le meme au moment ou j'envoi mes données. Mais je n'arrive pas a savoir pourquoi....



Des idées?



Thomas

Réponses

  • CéroceCéroce Membre, Modérateur
    janvier 2013 modifié #2
    Je n'ai pas (encore) d'expérience avec RESTKit, mais je mets en doute ton affirmation:


    'tplessis' a écrit:


    moment de mettre à  jour le compte de l'utilisateur et là , impossible de mettre a jour les données dans CoreData, rien ne se passe....


    A priori, si ce sont des données à  jour qui sont envoyées au serveur, alors les données sont forcément à  jour dans le MOC (Managed Object Context), puisque c'est là  que RESTKit vient les chercher.



    Un manière de t'en assurer est d'ouvrir la base SQLite avec un éditeur. Il faudra mettre à  jour le fichier en envoyant un -save au MOC.



    En espérant que cela puisse t'aider.





    P.S.: Merci de faire attention dans quelle section tu postes, ça n'a rien à  faire dans Vos projets d'applications.
  • Justement, je vérifie dans la base SQLite de l'appli que mes données sont bien à  jour et ce n'est pas le cas. En fait c'est au moment de mapper l'objet renvoyé par le webservice (dont les données sont bonnes) que RestKit se trompe en mappant ce résultat avec celui stocké dans CoreData, sans le mettre à  jour. Peut etre un probleme de cache?



    PS: Pardon pour le mauvais forum, je ferais gaffe la prochaine fois. image/wink.png' class='bbc_emoticon' alt=';)' />


    'Céroce' a écrit:


    Je n'ai pas (encore) d'expérience avec RESTKit, mais je mets en doute ton affirmation:





    A priori, si ce sont des données à  jour qui sont envoyées au serveur, alors les données sont forcément à  jour dans le MOC (Managed Object Context), puisque c'est là  que RESTKit vient les chercher.



    Un manière de t'en assurer est d'ouvrir la base SQLite avec un éditeur. Il faudra mettre à  jour le fichier en envoyant un -save au MOC.



    En espérant que cela puisse t'aider.





    P.S.: Merci de faire attention dans quelle section tu postes, ça n'a rien à  faire dans Vos projets d'applications.
  • es-tu certain d'être dans le main thread lorsque tu sauvegardes le MOC ?!
  • MarcioMarcio Membre
    février 2013 modifié #5
    Bonjour,



    Quand tu fais une sous classe de NSManagedObject tu ne dois pas mettre @synthesize pour tes variables d'instance qui sont sauvegardées dans CoreData mais plutôt @dynamic. NSManagedObject s'occupera au runtime de "créer" les setters qui vont bien pour sauvegarder en base.



    En espérant que ça corrige ton problème image/smile.png' class='bbc_emoticon' alt=':)' />
  • CéroceCéroce Membre, Modérateur
    Ah oui, pas vu!

    Effectivement, ça explique carrément le problème observé, mais pas pourquoi ça apparaà®trait dans la base SQLite, alors.
Connectez-vous ou Inscrivez-vous pour répondre.