Simplification de l'utilisation de l'API RESTful et de la persistance des données sur iOS avec Mantle et Realm

Publié: 2022-03-11

Chaque développeur iOS connaît Core Data, un framework de graphes d'objets et de persistance d'Apple. Outre la persistance des données localement, le framework est livré avec une multitude de fonctionnalités avancées, telles que le suivi des modifications d'objets et l'annulation. Ces fonctionnalités, bien qu'utiles dans de nombreux cas, ne sont pas gratuites. Cela nécessite beaucoup de code passe-partout, et le framework dans son ensemble a une courbe d'apprentissage abrupte.

En 2014, Realm, une base de données mobile, a été lancée et a pris d'assaut le monde du développement. Si tout ce dont nous avons besoin est de conserver les données localement, Realm est une bonne alternative. Après tout, tous les cas d'utilisation ne nécessitent pas les fonctionnalités avancées de Core Data. Realm est extrêmement facile à utiliser et, contrairement à Core Data, nécessite très peu de code passe-partout. Il est également thread-safe et serait plus rapide que le framework de persistance d'Apple.

Dans la plupart des applications mobiles modernes, les données persistantes résolvent la moitié du problème. Nous avons souvent besoin de récupérer des données à partir d'un service distant, généralement via une API RESTful. C'est là que Mantle entre en jeu. Il s'agit d'un cadre de modèle open source pour Cocoa et Cocoa Touch. Mantle simplifie considérablement l'écriture de modèles de données pour interagir avec les API qui utilisent JSON comme format d'échange de données.

Royaume et manteau pour iOS

Dans cet article, nous allons créer une application iOS qui récupère une liste d'articles ainsi que des liens vers ceux-ci à partir de l'API de recherche d'articles du New York Times v2. La liste va être récupérée à l'aide d'une requête HTTP GET standard, avec des modèles de requête et de réponse créés à l'aide de Mantle. Nous verrons à quel point il est facile avec Mantle de gérer les transformations de valeur (par exemple, de NSDate à string). Une fois les données récupérées, nous les conserverons localement en utilisant Realm. Tout cela avec un code passe-partout minimal.

API RESTful - Mise en route

Commençons par créer un nouveau projet Xcode "Master-Detail Application" pour iOS nommé "RealmMantleTutorial". Nous y ajouterons des frameworks en utilisant CocoaPods. Le podfile doit ressembler à ce qui suit :

 pod 'Mantle' pod 'Realm' pod 'AFNetworking'

Une fois les pods installés, nous pouvons ouvrir l'espace de travail MantleRealmTutorial nouvellement créé. Comme vous l'avez remarqué, le célèbre framework AFNetworking a également été installé. Nous l'utiliserons pour effectuer des requêtes à l'API.

Comme mentionné dans l'introduction, le New York Times fournit une excellente API de recherche d'articles. Pour l'utiliser, il faut s'inscrire pour obtenir une clé d'accès à l'API. Cela peut être fait sur http://developer.nytimes.com. Avec la clé API en main, nous sommes prêts à commencer le codage.

Avant de nous plonger dans la création de modèles de données Mantle, nous devons rendre notre couche réseau opérationnelle. Créons un nouveau groupe dans Xcode et appelons-le Réseau. Dans ce groupe, nous allons créer deux classes. Appelons le premier SessionManager et assurons-nous qu'il est dérivé de AFHTTPSessionManager qui est une classe de gestionnaire de session de AFNetworking , le charmant framework de mise en réseau. Notre classe SessionManager sera un objet singleton que nous utiliserons pour effectuer des requêtes get à l'API. Une fois la classe créée, veuillez copier le code ci-dessous dans les fichiers d'interface et d'implémentation respectivement.

 #import "AFHTTPSessionManager.h" @interface SessionManager : AFHTTPSessionManager + (id)sharedManager; @end
 #import "SessionManager.h" static NSString *const kBaseURL = @"http://api.nytimes.com"; @implementation SessionManager - (id)init { self = [super initWithBaseURL:[NSURL URLWithString:kBaseURL]]; if(!self) return nil; self.responseSerializer = [AFJSONResponseSerializer serializer]; self.requestSerializer = [AFJSONRequestSerializer serializer]; return self; } + (id)sharedManager { static SessionManager *_sessionManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sessionManager = [[self alloc] init]; }); return _sessionManager; } @end

Le gestionnaire de session est initialisé avec l'URL de base définie dans la variable statique kBaseURL . Il utilisera également les sérialiseurs de requête et de réponse JSON.

Maintenant, la deuxième classe que nous allons créer dans le groupe Network s'appellera APIManager . Il doit être dérivé de notre classe SessionManager nouvellement créée. Une fois les modèles de données nécessaires créés, nous ajouterons une méthode à ApiManager qui sera utilisée pour demander une liste d'articles à l'API.

Présentation de l'API de recherche d'articles du New York Times

La documentation officielle de cette excellente API est disponible sur http://developer.nytimes.com/…/article_search_api_v2. Ce que nous allons faire, c'est utiliser le point de terminaison suivant :

 http://api.nytimes.com/svc/search/v2/articlesearch

… pour récupérer les articles trouvés à l'aide d'un terme de requête de recherche de notre choix délimité par une plage de dates. Par exemple, nous pourrions demander à l'API de renvoyer une liste de tous les articles parus dans le New York Times qui avaient quelque chose à voir avec le basket-ball au cours des sept premiers jours de juillet 2015. Selon la documentation de l'API, pour ce faire nous devons définir les paramètres suivants dans la requête get à ce point de terminaison :

Paramètre Évaluer
q "basket-ball"
date de début "20150701"
date de fin "20150707"

La réponse de l'API est assez complexe. Vous trouverez ci-dessous la réponse à une demande avec les paramètres ci-dessus limités à un seul article (un élément dans le tableau docs) avec de nombreux champs omis pour plus de clarté.

 { "response": { "docs": [ { "web_url": "http://www.nytimes.com/2015/07/04/sports/basketball/robin-lopez-and-knicks-are-close-to-a-deal.html", "lead_paragraph": "Lopez, a 7-foot center, joined Arron Afflalo, a 6-foot-5 guard, as the Knicks' key acquisitions in free agency. He is expected to solidify the Knicks' interior defense.", "abstract": null, "print_page": "1", "source": "The New York Times", "pub_date": "2015-07-04T00:00:00Z", "document_type": "article", "news_desk": "Sports", "section_name": "Sports", "subsection_name": "Pro Basketball", "type_of_material": "News", "_id": "5596e7ac38f0d84c0655cb28", "word_count": "879" } ] }, "status": "OK", "copyright": "Copyright (c) 2013 The New York Times Company. All Rights Reserved." }

Ce que nous obtenons essentiellement en réponse, ce sont trois champs. Le premier appelé response contient le tableau docs , qui à son tour contient des éléments représentant des articles. Les deux autres champs sont status et copyright . Maintenant que nous savons comment fonctionne l'API, il est temps de créer des modèles de données à l'aide de Mantle.

Introduction au manteau

Comme mentionné précédemment, Mantle est un framework open source qui simplifie considérablement l'écriture de modèles de données. Commençons par créer un modèle de demande de liste d'articles. Appelons cette classe ArticleListRequestModel et assurons-nous qu'elle est dérivée de MTLModel , qui est une classe dont tous les modèles Mantle doivent être dérivés. De plus, rendons-le conforme au protocole MTLJSONSerializing . Notre modèle de requête doit avoir trois propriétés de types appropriés : query, articlesFromDate et articlesToDate . Juste pour m'assurer que notre projet est bien organisé, je suggère que cette classe soit placée dans le groupe Modèles .

Mantle simplifie l'écriture de modèles de données, réduit le code passe-partout.
Tweeter

Voici à quoi devrait ressembler le fichier d'interface de ArticleListRequestModel :

 #import "MTLModel.h" #import "Mantle.h" @interface ArticleListRequestModel : MTLModel <MTLJSONSerializing> @property (nonatomic, copy) NSString *query; @property (nonatomic, copy) NSDate *articlesFromDate; @property (nonatomic, copy) NSDate *articlesToDate; @end

Maintenant, si nous recherchons la documentation de notre point de terminaison de recherche d'articles ou si nous examinons le tableau avec les paramètres de demande ci-dessus, nous remarquerons que les noms des variables dans la demande d'API diffèrent de ceux de notre modèle de demande. Mantle gère cela efficacement en utilisant la méthode :

 + (NSDictionary *)JSONKeyPathsByPropertyKey.

Voici comment cette méthode doit être implémentée dans l'implémentation de notre modèle de requête :

 #import "ArticleListRequestModel.h" @implementation ArticleListRequestModel #pragma mark - Mantle JSONKeyPathsByPropertyKey + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"query": @"q", @"articlesFromDate": @"begin_date", @"articlesToDate": @"end_date" }; } @end

L'implémentation de cette méthode spécifie comment les propriétés du modèle sont mappées dans ses représentations JSON. Une fois la méthode JSONKeyPathsByPropertyKey implémentée, nous pouvons obtenir une représentation du dictionnaire JSON du modèle avec la méthode de classe +[MTLJSONAdapter JSONArrayForModels:] .

Une chose qui reste, comme nous le savons d'après la liste des paramètres, est que les deux paramètres de date doivent être au format "AAAAMMJJ". C'est là que Mantle devient très pratique. Nous pouvons ajouter une transformation de valeur personnalisée pour n'importe quelle propriété en implémentant la méthode facultative +<propertyName>JSONTransformer . En l'implémentant, nous indiquons à Mantle comment la valeur d'un champ JSON spécifique doit être transformée lors de la désérialisation JSON. Nous pouvons également implémenter un transformateur réversible qui sera utilisé lors de la création d'un JSON à partir du modèle. Comme nous devons transformer un objet NSDate en chaîne, nous utiliserons également la classe NSDataFormatter . Voici l'implémentation complète de la classe ArticleListRequestModel :

 #import "ArticleListRequestModel.h" @implementation ArticleListRequestModel + (NSDateFormatter *)dateFormatter { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"yyyyMMdd"; return dateFormatter; } #pragma mark - Mantle JSONKeyPathsByPropertyKey + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"query": @"q", @"articlesFromDate": @"begin_date", @"articlesToDate": @"end_date" }; } #pragma mark - JSON Transformers + (NSValueTransformer *)articlesToDateJSONTransformer { return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) { return [self.dateFormatter dateFromString:dateString]; } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) { return [self.dateFormatter stringFromDate:date]; }]; } + (NSValueTransformer *)articlesFromDateJSONTransformer { return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) { return [self.dateFormatter dateFromString:dateString]; } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) { return [self.dateFormatter stringFromDate:date]; }]; } @end

Une autre grande caractéristique de Mantle est que tous ces modèles sont conformes au protocole NSCoding et implémentent les méthodes isEqual et hash .

Comme nous l'avons déjà vu, le JSON résultant de l'appel d'API contient un tableau d'objets qui représentent des articles. Si nous voulons modéliser cette réponse à l'aide de Mantle, nous devrons créer deux modèles de données distincts. L'un modéliserait des objets représentant des articles (éléments de tableau docs ), et l'autre modéliserait l'ensemble de la réponse JSON à l'exception des éléments du tableau docs. Désormais, nous n'avons plus besoin de mapper chaque propriété du JSON entrant dans nos modèles de données. Supposons que nous ne soyons intéressés que par deux champs d'objets article, et ceux-ci seraient lead_paragraph et web_url . La classe ArticleModel est assez simple à implémenter, comme nous pouvons le voir ci-dessous.

 #import "MTLModel.h" #import <Mantle/Mantle.h> @interface ArticleModel : MTLModel <MTLJSONSerializing> @property (nonatomic, copy) NSString *leadParagraph; @property (nonatomic, copy) NSString *url; @end
 #import "ArticleModel.h" @implementation ArticleModel #pragma mark - Mantle JSONKeyPathsByPropertyKey + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"leadParagraph": @"lead_paragraph", @"url": @"web_url" }; } @end

Maintenant que le modèle d'article a été défini, nous pouvons terminer la définition du modèle de réponse en créant un modèle pour la liste d'articles. Voici à quoi ressemblera le modèle de réponse de la classe ArticleList.

 #import "MTLModel.h" #import <Mantle/Mantle.h> #import "ArticleModel.h" @interface ArticleListResponseModel : MTLModel <MTLJSONSerializing> @property (nonatomic, copy) NSArray *articles; @property (nonatomic, copy) NSString *status; @end
 #import "ArticleListResponseModel.h" @class ArticleModel; @implementation ArticleListResponseModel #pragma mark - Mantle JSONKeyPathsByPropertyKey + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"articles" : @"response.docs", @"status" : @"status" }; } #pragma mark - JSON Transformer + (NSValueTransformer *)articlesJSONTransformer { return [MTLJSONAdapter arrayTransformerWithModelClass:ArticleModel.class]; } @end

Cette classe n'a que deux propriétés : status et articles . Si nous le comparons à la réponse du point de terminaison, nous verrons que le troisième attribut JSON copyright ne sera pas mappé dans le modèle de réponse. Si nous regardons la méthode articlesJSONTransformer , nous verrons qu'elle renvoie un transformateur de valeur pour un tableau contenant des objets de la classe ArticleModel .

Il convient également de noter que dans la méthode JSONKeyPathsByPropertyKey , les articles de la propriété du modèle correspondent au tableau docs imbriqué dans la réponse de l'attribut JSON .

À présent, nous devrions avoir trois classes de modèles implémentées : ArticleListRequestModel, ArticleModel et ArticleListResponseModel.

Première demande d'API

API reposante

Maintenant que nous avons implémenté tous les modèles de données, il est temps de revenir à la classe APIManager pour implémenter la méthode que nous allons utiliser pour effectuer des requêtes GET à l'API. La méthode:

 - (NSURLSessionDataTask *) getArticlesWithRequestModel:(ArticleListRequestModel *)requestModel success:(void (^)(ArticleListResponseModel *responseModel))success failure:(void (^)(NSError *error))failure

prend un modèle de requête ArticleListRequestModel comme paramètre et renvoie un ArticleListResponseModel en cas de succès ou une NSError dans le cas contraire. L'implémentation de cette méthode utilise AFNetworking pour effectuer une requête GET à l'API. Veuillez noter que pour faire une demande d'API réussie, nous devons fournir une clé qui peut être obtenue comme mentionné précédemment, en vous inscrivant sur http://developer.nytimes.com.

 #import "SessionManager.h" #import "ArticleListRequestModel.h" #import "ArticleListResponseModel.h" @interface APIManager : SessionManager - (NSURLSessionDataTask *)getArticlesWithRequestModel:(ArticleListRequestModel *)requestModel success:(void (^)(ArticleListResponseModel *responseModel))success failure:(void (^)(NSError *error))failure; @end
 #import "APIManager.h" #import "Mantle.h" static NSString *const kArticlesListPath = @"/svc/search/v2/articlesearch.json"; static NSString *const kApiKey = @"replace this with your own key"; @implementation APIManager - (NSURLSessionDataTask *)getArticlesWithRequestModel:(ArticleListRequestModel *)requestModel success:(void (^)(ArticleListResponseModel *responseModel))success failure:(void (^)(NSError *error))failure{ NSDictionary *parameters = [MTLJSONAdapter JSONDictionaryFromModel:requestModel error:nil]; NSMutableDictionary *parametersWithKey = [[NSMutableDictionary alloc] initWithDictionary:parameters]; [parametersWithKey setObject:kApiKey forKey:@"api-key"]; return [self GET:kArticlesListPath parameters:parametersWithKey success:^(NSURLSessionDataTask *task, id responseObject) { NSDictionary *responseDictionary = (NSDictionary *)responseObject; NSError *error; ArticleListResponseModel *list = [MTLJSONAdapter modelOfClass:ArticleListResponseModel.class fromJSONDictionary:responseDictionary error:&error]; success(list); } failure:^(NSURLSessionDataTask *task, NSError *error) { failure(error); }]; }

Il y a deux choses très importantes qui se passent dans la mise en œuvre de cette méthode. Voyons d'abord cette ligne :

 NSDictionary *parameters = [MTLJSONAdapter JSONDictionaryFromModel:requestModel error:nil];

Ce qui se passe ici, c'est qu'en utilisant la méthode fournie par la classe MTLJSONAdapter , nous obtenons une représentation NSDictionary de notre modèle de données. Cette représentation reflète le JSON qui va être envoyé à l'API. C'est là que réside la beauté de Mantle. Après avoir implémenté les méthodes JSONKeyPathsByPropertyKey et +<propertyName>JSONTransformer dans la classe ArticleListRequestModel, nous pouvons obtenir la représentation JSON correcte de notre modèle de données en un rien de temps avec une seule ligne de code.

Mantle nous permet également d'effectuer des transformations dans l'autre sens. Et c'est exactement ce qui se passe avec les données reçues de l'API. Le NSDictionary que nous recevons est mappé dans un objet de la classe ArticleListResponseModel à l'aide de la méthode de classe suivante :

 ArticleListResponseModel *list = [MTLJSONAdapter modelOfClass:ArticleListResponseModel.class fromJSONDictionary:responseDictionary error:&error];

Données persistantes avec Realm

Maintenant que nous sommes en mesure de récupérer des données à partir d'une API distante, il est temps de les conserver. Comme mentionné dans l'introduction, nous le ferons en utilisant Realm. Realm est une base de données mobile et remplace Core Data et SQLite. Comme nous le verrons ci-dessous, il est extrêmement facile à utiliser.

Realm, la base de données mobile ultime, remplace parfaitement Core Data et SQLite.
Tweeter

Pour enregistrer une donnée dans Realm, nous devons d'abord encapsuler un objet dérivé de la classe RLMObject. Ce que nous devons faire maintenant est de créer une classe de modèle qui stockera les données d'articles uniques. Voici à quel point il est facile de créer une telle classe.

 #import "RLMObject.h" @interface ArticleRealm : RLMObject @property NSString *leadParagraph; @property NSString *url; @end

Et ça pourrait être fondamentalement ça, l'implémentation de cette classe pourrait rester vide. Veuillez noter que les propriétés de la classe de modèle n'ont pas d'attributs tels que non atomique, fort ou copie. Realm s'en occupe et nous n'avons pas à nous en soucier.

Étant donné que les articles que nous pouvons obtenir sont modélisés avec le modèle Mante Article , il serait pratique d'initialiser les objets ArticleRealm avec des objets de la classe Article . Pour ce faire, nous ajouterons la méthode initWithMantleModel à notre modèle Realm. Voici l'implémentation complète de la classe ArticleRealm .

 #import "RLMObject.h" #import "ArticleModel.h" @interface ArticleRealm : RLMObject @property NSString *leadParagraph; @property NSString *url; - (id)initWithMantleModel:(ArticleModel *)articleModel; @end
 #import "ArticleRealm.h" @implementation ArticleRealm - (id)initWithMantleModel:(ArticleModel *)articleModel{ self = [super init]; if(!self) return nil; self.leadParagraph = articleModel.leadParagraph; self.url = articleModel.url; return self; } @end

Nous interagissons avec la base de données en utilisant des objets de la classe RLMRealm . Nous pouvons facilement obtenir un objet RLMRealm en invoquant la méthode "[RLMRealm defaultRealm]". Il est important de se rappeler qu'un tel objet n'est valide que dans le thread sur lequel il a été créé et ne peut pas être partagé entre les threads. L'écriture de données dans Realm est assez simple. Une seule écriture, ou une série d'écritures, doit être effectuée dans une transaction d'écriture. Voici un exemple d'écriture dans la base de données :

 RLMRealm *realm = [RLMRealm defaultRealm]; ArticleRealm *articleRealm = [ArticleRealm new]; articleRealm.leadParagraph = @"abc"; articleRealm.url = @"sampleUrl"; [realm beginWriteTransaction]; [realm addObject:articleRealm]; [realm commitWriteTransaction];

Ce qui se passe ici est le suivant. Nous créons d'abord un objet RLMRealm pour interagir avec la base de données. Ensuite, un objet de modèle ArticleRealm est créé (veuillez garder à l'esprit qu'il est dérivé de la classe RLMRealm ). Enfin, pour le sauvegarder, une transaction d'écriture commence, l'objet est ajouté à la base de données et une fois qu'il est sauvegardé, la transaction d'écriture est validée. Comme nous pouvons le voir, les transactions d'écriture bloquent le thread sur lequel elles sont invoquées. Alors que Realm est censé être très rapide, si nous devions ajouter plusieurs objets à la base de données dans une seule transaction sur le thread principal, cela pourrait empêcher l'interface utilisateur de répondre jusqu'à ce que la transaction soit terminée. Une solution naturelle à cela consiste à effectuer une telle transaction d'écriture sur un thread d'arrière-plan.

Demande d'API et réponse persistante dans le domaine

Ce sont toutes les informations dont nous avons besoin pour conserver les articles en utilisant Realm. Essayons d'effectuer une requête API en utilisant la méthode

 - (NSURLSessionDataTask *) getArticlesWithRequestModel:(ArticleListRequestModel *)requestModel success:(void (^)(ArticleListResponseModel *responseModel))success failure:(void (^)(NSError *error))failure

et les modèles de demande et de réponse Mantle afin d'obtenir des articles du New York Times qui avaient quelque chose à voir (comme dans l'exemple précédent) avec le basket-ball et qui ont été publiés dans les sept premiers jours de juin 2015. Une fois la liste de ces articles disponible, nous le persistera dans Realm. Vous trouverez ci-dessous le code qui fait cela. Il est placé dans la méthode viewDidLoad du contrôleur de vue de table dans notre application.

 ArticleListRequestModel *requestModel = [ArticleListRequestModel new]; // (1) requestModel.query = @"Basketball"; requestModel.articlesToDate = [[ArticleListRequestModel dateFormatter] dateFromString:@"20150706"]; requestModel.articlesFromDate = [[ArticleListRequestModel dateFormatter] dateFromString:@"20150701"]; [[APIManager sharedManager] getArticlesWithRequestModel:requestModel // (2) success:^(ArticleListResponseModel *responseModel){ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // (3) @autoreleasepool { RLMRealm *realm = [RLMRealm defaultRealm]; [realm beginWriteTransaction]; [realm deleteAllObjects]; [realm commitWriteTransaction]; [realm beginWriteTransaction]; for(ArticleModel *article in responseModel.articles){ ArticleRealm *articleRealm = [[ArticleRealm alloc] initWithMantleModel:article]; // (4) [realm addObject:articleRealm]; } [realm commitWriteTransaction]; dispatch_async(dispatch_get_main_queue(), ^{ // (5) RLMRealm *realmMainThread = [RLMRealm defaultRealm]; // (6) RLMResults *articles = [ArticleRealm allObjectsInRealm:realmMainThread]; self.articles = articles; // (7) [self.tableView reloadData]; }); } }); } failure:^(NSError *error) { self.articles = [ArticleRealm allObjects]; [self.tableView reloadData]; }];

Tout d'abord, un appel API est effectué (2) avec un modèle de requête (1), qui renvoie un modèle de réponse contenant une liste d'articles. Afin de conserver ces articles à l'aide de Realm, nous devons créer des objets de modèle Realm, qui ont lieu dans la boucle for (4). Il est également important de noter que puisque plusieurs objets sont conservés dans une seule transaction d'écriture, cette transaction d'écriture est effectuée sur un thread d'arrière-plan (3). Maintenant, une fois que tous les articles sont enregistrés dans Realm, nous les attribuons à la propriété de classe self.articles (7). Puisqu'ils seront accessibles ultérieurement sur le thread principal dans les méthodes de source de données TableView, il est également possible de les récupérer en toute sécurité à partir de la base de données Realm sur le thread principal (5). Encore une fois, pour accéder à la base de données à partir d'un nouveau thread, un nouvel objet RLMRealm doit être créé (6) sur ce thread.

Si l'obtention de nouveaux articles à partir de l'API échoue pour une raison quelconque, les articles existants sont récupérés à partir du stockage local dans le bloc d'échec.

Emballer

Dans ce tutoriel, nous avons appris à configurer Mantle, un framework modèle pour Cocoa et Cocoa Touch, afin d'interagir avec une API distante. Nous avons également appris à conserver localement les données récupérées sous la forme d'objets de modèle Mantle à l'aide de la base de données mobile Realm.

Si vous souhaitez essayer cette application, vous pouvez récupérer le code source à partir de son référentiel GitHub. Vous devrez générer et fournir votre propre clé API avant d'exécuter l'application.