MagicalRecord is Magical (Lib pour Core Data)

Salut tout le monde,



J'ai découvert une super librairie hier qui rend Core Data bien bien plus simple d'utilisation.



Alors je fais une recherche sur le forum pour voir si quelqu'un en parlait et niet, alors je viens partager avec vous !



ça s'appelle MagicalRecord et le code se trouve sur Github : https://github.com/magicalpanda/MagicalRecord



Pour faire simple, le but du MagicalRecord c'est de pouvoir faire du "tout sur une ligne".



Quelques exemples (pris directement depuis la readme github) :


<br />
NSArray *people = [Person findAll];<br />
//--------<br />
NSArray *peopleSorted = [Person findAllSortedByProperty:@&quot;LastName&quot; ascending:YES];<br />
//---------<br />
NSArray *peopleSorted = [Person findAllSortedByProperty:@&quot;LastName,FirstName&quot; ascending:YES];<br />
//---------<br />
Person *person = [Person findFirstByAttribute:@&quot;FirstName&quot; withValue:@&quot;Forrest&quot;];<br />
//---------<br />
NSArray *departments = [NSArray arrayWithObjects:dept1, dept2, ..., nil];<br />
NSPredicate *peopleFilter = [NSPredicate predicateWithFormat:@&quot;Department IN %@&quot;, departments];<br />
NSArray *people = [Person findAllWithPredicate:peopleFilter];<br />






Mais ce que j'aime le plus dans cette librairie ce sont la possibilité de faire facilement du Core Data en multithreading, avec des blocks :


<br />
Person *person = ...;<br />
[MRCoreDataAction saveDataInBackgroundWithBlock:^(NSManagedObjectContext *localContext){<br />
    Person *localPerson = [person inContext:localContext];<br />
    localPerson.firstName = @&quot;Chuck&quot;;<br />
    localPerson.lastName = @&quot;Smith&quot;;<br />
}];<br />
//-------<br />
Person *person = ...;<br />
[MRCoreDataAction saveDataInBackgroundWithBlock:^(NSManagedObjectContext *localContext){<br />
    Person *localPerson = [person inContext:localContext];<br />
    localPerson.firstName = @&quot;Chuck&quot;;<br />
    localPerson.lastName = @&quot;Smith&quot;;<br />
} completion:^{<br />
    self.everyoneInTheDepartment = [Person findAll];<br />
}];<br />




Pas mal non ? en parametre du block y'a un context fraichement créé pour le block, tout tourne avec Grand Central Dispatch, une petit block de completion.

Bref c'est parfait image/biggrin.png' class='bbc_emoticon' alt=':D' />



Y'a un support de iCloud, ARC et plein de petits trucs. Et ils sont en train de travailler sur une fonction d'import (insert/update) depuis des NSArray/NSDictionary.





Enfin voilà , c'était le petit partage du jour.



But One more thing : si vous voulez visualiser votre base SQLite (ou MySQL, PostgreSQL, ou même MongoDB) voici une application open source plutôt efficace : http://inductionapp.com/ image/wink.png' class='bbc_emoticon' alt=';)' />
Mots clés:

Réponses

  • KixxxKixxx Membre
    Ah merci, je garde pour un prochain projet image/wink.png' class='bbc_emoticon' alt=';)' />
  • Je connaissais cette lib mais j'ai jamais franchi le cap mais en effet elle a l'air très sympa !

    J'ai vu ton post sur twitter pour induction image/smile.png' class='bbc_emoticon' alt=':)' />
  • Faudrait que je regarde ça de plus prêt car au vu des exemples je ne comprends pas trop en quoi ça rend core data bien plus simple d'utilisation.
  • JegnuXJegnuX Membre
    mars 2012 modifié #5
    'Kubernan' a écrit:


    Faudrait que je regarde ça de plus prêt car au vu des exemples je ne comprends pas trop en quoi ça rend core data bien plus simple d'utilisation.




    Plus pratique si tu préfères ?



    Par exemple ça :


    Person *person = [Person findFirstByAttribute:@&quot;FirstName&quot; withValue:@&quot;Forrest&quot;];<br />
    




    Sans la lib faut faire un truc du genre :
    Person *person = nil;<br />
    NSManagedObjectContext *moc = [self managedObjectContext];<br />
    NSEntityDescription *entityDescription = [NSEntityDescription<br />
    	entityForName:@&quot;Person&quot; inManagedObjectContext:moc];<br />
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];<br />
    [request setEntity:entityDescription];<br />
    <br />
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@&quot;FirstName LIKE[c] &#39;Forrest&#39;&quot;];<br />
    [request setPredicate:predicate];<br />
    <br />
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]<br />
    	initWithKey:@&quot;FirstName&quot; ascending:YES];<br />
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];<br />
    [sortDescriptor release];<br />
    <br />
    NSError *error = nil;<br />
    NSArray *array = [moc executeFetchRequest:request error:&amp;error];<br />
    if (array == nil || [array count] == 0)<br />
    {<br />
    	// Deal with error...<br />
    }<br />
    else<br />
    {<br />
    	person = [array objectAtIndex:0];<br />
    }<br />
    




    Tu vois mieux ? image/smile.png' class='bbc_emoticon' alt=':)' />



    Mais comme je dis, là  où c'est vraiment le must, c'est quand on fait du multithread image/wink.png' class='bbc_emoticon' alt=';)' />
  • Moi je préfère la seconde méthode perso image/xd-laugh.gif' class='bbc_emoticon' alt='xd' />

    Pour le multithread j'avoue c'est vraiment sympa avec le block de completion.
  • JegnuXJegnuX Membre
    mars 2012 modifié #7
    'Ceetix' a écrit:


    Moi je préfère la seconde méthode perso image/xd-laugh.gif' class='bbc_emoticon' alt='xd' />

    Pour le multithread j'avoue c'est vraiment sympa avec le block de completion.




    Bah moi j'aime pas me faire chier...

    Je m'étais déjà  fais un petit helper à  part, car dans la plupart des cas c'est toujours le même genre de requêtes, et franchement ce gros bloc de code bah quand t'en a plein tu perds en lisibilité. Donc j'essaie de raccourcir au max. Tout comme j'ai un Helper pour formater mes dates car ça devient vite relou.



    Et du coup, au lieu de réinventer la roue, bah là  j'ai une lib hyper complète avec une bonne communauté derrière.
  • C'était ironique hein lol

    Pareil je m'étais fait une petite classe de requêtage pour Core Data.
  • 'Ceetix' a écrit:


    C'était ironique hein lol




    Ah... Bon bah je me tais alors... image/sleep.png' class='bbc_emoticon' alt='-_-' />
  • Oui je vois... image/implore.gif' class='bbc_emoticon' alt=' o:) ' /> tu peux quand même remplacer les premières lignes par un
    <br />
    NSFetchRequest *reqPerson = [NSFetchRequest fetchRequestWithEntityName:@&quot;Person&quot;];<br />
    




    Bon j'ai l'air de chipoter mais comme j'ai dit faudrait que je regarde ça de plus prêt en comparant avec mes besoins.

    Par exemple :
    <br />
    NSFetchRequest *reqDynSum = [NSFetchRequest fetchRequestWithEntityName:@&quot;List&quot;];<br />
    	    NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@&quot;value&quot;];<br />
    	    NSExpression *sumExpression = [NSExpression expressionForFunction:@&quot;sum:&quot; arguments:[NSArray arrayWithObject:keyPathExpression]];<br />
    	    NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];<br />
    	    [expressionDescription setName:@&quot;sumValue&quot;];<br />
    	    [expressionDescription setExpression:sumExpression];<br />
    	    [expressionDescription setExpressionResultType:NSDecimalAttributeType];<br />
    <br />
    [reqDynSum [color=#40267f]setPropertiesToFetch[/color]:[[color=#7042a6]NSArray[/color] [color=#40267f]arrayWithObject[/color]:expressionDescription]];<br />
    ...<br />
    




    Pour le multithread le block complétion est sympa. Actuellement j'utilise deux méthodes : des NSOperation pour les gros traitements (avec un concurrency type à  NSPrivateQueueConcurrencyType) et le performBlock du context courant pour des petites requêtes qui pourraient bloquer l'affichage.
  • 'Kubernan' a écrit:


    Oui je vois... image/implore.gif' class='bbc_emoticon' alt=' o:) ' /> tu peux quand même remplacer les premières lignes par un
    <br />
    NSFetchRequest *reqPerson = [NSFetchRequest fetchRequestWithEntityName:@&quot;Person&quot;];<br />
    




    Bon j'ai l'air de chipoter mais comme j'ai dit faudrait que je regarde ça de plus prêt en comparant avec mes besoins.

    Par exemple :
    <br />
    NSFetchRequest *reqDynSum = [NSFetchRequest fetchRequestWithEntityName:@&quot;List&quot;];<br />
    		NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@&quot;value&quot;];<br />
    		NSExpression *sumExpression = [NSExpression expressionForFunction:@&quot;sum:&quot; arguments:[NSArray arrayWithObject:keyPathExpression]];<br />
    		NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];<br />
    		[expressionDescription setName:@&quot;sumValue&quot;];<br />
    		[expressionDescription setExpression:sumExpression];<br />
    		[expressionDescription setExpressionResultType:NSDecimalAttributeType];<br />
    <br />
    [reqDynSum [color=#40267f]setPropertiesToFetch[/color]:[[color=#7042a6]NSArray[/color] [color=#40267f]arrayWithObject[/color]:expressionDescription]];<br />
    ...<br />
    




    Pour le multithread le block complétion est sympa. Actuellement j'utilise deux méthodes : des NSOperation pour les gros traitements (avec un concurrency type à  NSPrivateQueueConcurrencyType) et le performBlock du context courant pour des petites requêtes qui pourraient bloquer l'affichage.






    Et bim :


    <br />
    double sum = [[List aggregateOperation:@&quot;sum:&quot; onAttribute:@&quot;value&quot; withPredicate:nil] doubleValue];<br />
    
  • 'JegnuX' a écrit:
    Et bim :
    double sum = [[List aggregateOperation:@&quot;sum:&quot; onAttribute:@&quot;value&quot; withPredicate:nil] doubleValue];
    




    Pan dans les dents. Merci d'avoir pris le temps :-) Je vais donc regarder ça de plus prêt.
  • 'Kubernan' a écrit:


    Pan dans les dents. Merci d'avoir pris le temps :-) Je vais donc regarder ça de plus prêt.




    Après je dis pas que cette lib pourra couvrir tout les cas de ce qu'on peut faire avec Core Data, c'est sûr. Mais c'est open source, rien n'empêche de proposer des evols image/smile.png' class='bbc_emoticon' alt=':)' />



    Enfin voilà  perso, je trouve que ça fait gagner pas mal de temps.



    Au fait, petite subtilité : par défaut toutes les méthodes doivent être précédées de MR_ :
    <br />
    Person *person = [Person MR_findFirstByAttribute:@&quot;FirstName&quot; withValue:@&quot;Forrest&quot;];<br />
    




    Mais pour faire direct sans MR_ il faut juste rajouter un define dans le prefix :
    <br />
    #define MR_SHORTHAND<br />
    
Connectez-vous ou Inscrivez-vous pour répondre.