تبسيط استخدام RESTful API واستمرار البيانات على iOS مع Mantle and Realm
نشرت: 2022-03-11كل مطور iOS على دراية بـ Core Data ، وهو رسم بياني للكائنات وإطار عمل استمرارية من Apple. بصرف النظر عن البيانات المستمرة محليًا ، يأتي إطار العمل مزودًا بمجموعة من الميزات المتقدمة ، مثل تتبع تغيير الكائن والتراجع. على الرغم من أن هذه الميزات مفيدة في كثير من الحالات ، إلا أنها لا تأتي مجانًا. يتطلب الكثير من التعليمات البرمجية المعيارية ، والإطار ككل له منحنى تعليمي حاد.
في عام 2014 ، تم إصدار Realm ، وهي قاعدة بيانات متنقلة ، وأخذت عالم التنمية في طريق العاصفة. إذا كان كل ما نحتاجه هو الحفاظ على البيانات محليًا ، فإن Realm يعد بديلاً جيدًا. بعد كل شيء ، لا تتطلب جميع حالات الاستخدام الميزات المتقدمة لـ Core Data. Realm سهل الاستخدام للغاية وعلى عكس البيانات الأساسية ، يتطلب القليل جدًا من التعليمات البرمجية المعيارية. إنه أيضًا آمن للخيط ويقال إنه أسرع من إطار عمل المثابرة من Apple.
في معظم تطبيقات الهاتف المحمول الحديثة ، تحل البيانات المستمرة نصف المشكلة. نحتاج غالبًا إلى جلب البيانات من خدمة بعيدة ، عادةً من خلال واجهة برمجة تطبيقات RESTful. هذا هو المكان الذي يلعب فيه Mantle. إنه إطار نموذج مفتوح المصدر لـ Cocoa و Cocoa Touch. يبسط Mantle بشكل كبير كتابة نماذج البيانات للتفاعل مع واجهات برمجة التطبيقات التي تستخدم JSON كتنسيق لتبادل البيانات.
في هذه المقالة ، سننشئ تطبيق iOS يجلب قائمة بالمقالات مع روابط لها من New York Times Article Search API v2. سيتم جلب القائمة باستخدام طلب HTTP GET قياسي ، مع نماذج الطلب والاستجابة التي تم إنشاؤها باستخدام Mantle. سوف نتعرف على مدى سهولة التعامل مع تحولات القيمة مع Mantle (على سبيل المثال ، من NSDate إلى السلسلة). بمجرد جلب البيانات ، سنستمر في استخدامها محليًا باستخدام Realm. كل هذا مع الحد الأدنى من التعليمات البرمجية المعيارية.
RESTful API - الشروع في العمل
لنبدأ بإنشاء مشروع Xcode "تطبيق رئيسي للتفاصيل" جديد لنظام iOS باسم "RealmMantleTutorial". سنقوم بإضافة أطر عمل إليه باستخدام CocoaPods. يجب أن يشبه ملف podfile ما يلي:
pod 'Mantle' pod 'Realm' pod 'AFNetworking'
بمجرد تثبيت الكبسولات ، يمكننا فتح مساحة عمل MantleRealmTutorial المنشأة حديثًا. كما لاحظت ، تم أيضًا تثبيت إطار عمل AFNetworking الشهير. سنستخدمه لتنفيذ الطلبات إلى واجهة برمجة التطبيقات.
كما هو مذكور في المقدمة ، توفر New York Times واجهة برمجة تطبيقات ممتازة للبحث عن المقالات. من أجل استخدامه ، يحتاج المرء إلى التسجيل للحصول على مفتاح وصول إلى واجهة برمجة التطبيقات. يمكن القيام بذلك على http://developer.nytimes.com. مع وجود مفتاح API في متناول اليد ، نحن على استعداد للبدء في الترميز.
قبل الخوض في إنشاء نماذج بيانات Mantle ، نحتاج إلى إعداد طبقة شبكتنا وتشغيلها. لنقم بإنشاء مجموعة جديدة في Xcode ونسميها Network. في هذه المجموعة سننشئ فصلين. دعنا نطلق على أول SessionManager ونتأكد من أنه مشتق من AFHTTPSessionManager وهو فئة مدير جلسة من AFNetworking ، إطار عمل شبكي مبهج. ستكون فئة SessionManager الخاصة بنا عبارة عن كائن مفرد سنستخدمه لتنفيذ طلبات الحصول على واجهة برمجة التطبيقات. بمجرد إنشاء الفصل ، يرجى نسخ الكود أدناه إلى ملفات الواجهة والتنفيذ على التوالي.
#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
تتم تهيئة مدير الجلسة بعنوان URL الأساسي المحدد في متغير kBaseURL الثابت. سيستخدم أيضًا مسلسلين للطلب والاستجابة JSON.
الآن الفئة الثانية التي سننشئها في مجموعة الشبكة ستسمى APIManager . يجب أن يكون مشتقًا من فئة SessionManager التي تم إنشاؤها حديثًا. بمجرد إنشاء نماذج البيانات الضرورية ، سنضيف طريقة إلى ApiManager سيتم استخدامها لطلب قائمة بالمقالات من واجهة برمجة التطبيقات.
نظرة عامة على واجهة برمجة تطبيقات بحث المقالات في New York Times
الوثائق الرسمية لواجهة برمجة التطبيقات الممتازة هذه متاحة على http://developer.nytimes.com/…/article_search_api_v2. ما سنفعله هو استخدام نقطة النهاية التالية:
http://api.nytimes.com/svc/search/v2/articlesearch
... لجلب المقالات التي تم العثور عليها باستخدام مصطلح استعلام بحث من اختيارنا مقيد بنطاق زمني. على سبيل المثال ، ما يمكننا فعله هو أن نطلب من API إعادة قائمة بجميع المقالات التي ظهرت في نيويورك تايمز والتي لها علاقة بكرة السلة في الأيام السبعة الأولى من يوليو 2015. وفقًا لوثائق API ، للقيام بذلك نحتاج إلى تعيين المعلمات التالية في طلب الحصول على نقطة النهاية هذه:
معامل | قيمة |
ف | "كرة سلة" |
موعد البدء | "20150701" |
تاريخ الانتهاء | "20150707" |
الاستجابة من API معقدة للغاية. يوجد أدناه الرد على طلب مع المعلمات المذكورة أعلاه تقتصر على مقال واحد فقط (عنصر واحد في مصفوفة المستندات) مع حذف العديد من الحقول من أجل التوضيح.
{ "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." }
ما نحصل عليه في الأساس استجابة هو ثلاثة مجالات. أول واحد يسمى الاستجابة يحتوي على مستندات المصفوفة ، والتي بدورها تحتوي على عناصر تمثل المقالات. المجالان الآخران هما الحالة وحقوق النشر . الآن بعد أن عرفنا كيفية عمل API ، حان الوقت لإنشاء نماذج بيانات باستخدام Mantle.
مقدمة إلى عباءة
كما ذكرنا سابقًا ، يعد Mantle إطار عمل مفتوح المصدر يبسط بشكل كبير كتابة نماذج البيانات. لنبدأ بإنشاء نموذج طلب قائمة المقالات. دعنا نسمي هذه الفئة ArticleListRequestModel ونتأكد من أنها مشتقة من MTLModel ، وهي فئة يجب اشتقاق جميع نماذج Mantle منها. بالإضافة إلى ذلك ، دعونا نجعلها متوافقة مع بروتوكول MTLJSONSerializing . يجب أن يحتوي نموذج الطلب الخاص بنا على ثلاث خصائص من الأنواع المناسبة: الاستعلام ، و ArticlesFromDate ، و ArticlesToDate . فقط للتأكد من أن مشروعنا منظم جيدًا ، أقترح وضع هذا الفصل في مجموعة العارضين .
إليك الشكل الذي يجب أن يظهر به ملف واجهة 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
الآن إذا بحثنا في المستندات عن نقطة نهاية بحث المقالة أو ألقينا نظرة على الجدول الذي يحتوي على معلمات الطلب أعلاه ، فسنلاحظ أن أسماء المتغيرات في طلب واجهة برمجة التطبيقات تختلف عن تلك الموجودة في نموذج الطلب الخاص بنا. يتعامل Mantle مع هذا بكفاءة باستخدام الطريقة:
+ (NSDictionary *)JSONKeyPathsByPropertyKey.
إليك كيفية تنفيذ هذه الطريقة في تنفيذ نموذج الطلب الخاص بنا:
#import "ArticleListRequestModel.h" @implementation ArticleListRequestModel #pragma mark - Mantle JSONKeyPathsByPropertyKey + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"query": @"q", @"articlesFromDate": @"begin_date", @"articlesToDate": @"end_date" }; } @end
يحدد تنفيذ هذه الطريقة كيفية تعيين خصائص النموذج في تمثيلات JSON الخاصة به. بمجرد تنفيذ الطريقة JSONKeyPathsByPropertyKey ، يمكننا الحصول على تمثيل قاموس JSON للنموذج باستخدام طريقة الفئة +[MTLJSONAdapter JSONArrayForModels:]
.
الشيء الوحيد المتبقي ، كما نعلم من قائمة المعلمات ، هو أن كلا معلمتَي التاريخ مطلوبان أن تكونا بالتنسيق "YYYYMMDD". هذا هو المكان الذي يصبح فيه Mantle مفيدًا جدًا. يمكننا إضافة تحويل قيمة مخصصة لأي خاصية من خلال تنفيذ الطريقة الاختيارية +<propertyName>JSONTransformer
. من خلال تنفيذه ، نخبر Mantle كيف يجب تحويل قيمة حقل JSON معين أثناء إلغاء تسلسل JSON. يمكننا أيضًا تنفيذ محول عكسي سيتم استخدامه عند إنشاء JSON من النموذج. نظرًا لأننا نحتاج إلى تحويل كائن NSDate إلى سلسلة ، فسنستخدم أيضًا فئة NSDataFormatter . هنا هو التنفيذ الكامل لفئة 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
ميزة أخرى رائعة لـ Mantle هي أن جميع هذه النماذج تتوافق مع بروتوكول NSCoding ، بالإضافة إلى تنفيذ طرق isEqual و hash .
كما رأينا بالفعل ، يحتوي JSON الناتج من استدعاء API على مجموعة من الكائنات التي تمثل المقالات. إذا أردنا نمذجة هذه الاستجابة باستخدام Mantle ، فسيتعين علينا إنشاء نموذجين منفصلين للبيانات. قد يقوم أحدهم بنمذجة كائنات تمثل المقالات (عناصر مصفوفة مستندات ) ، بينما يقوم الآخر بنمذجة استجابة JSON بالكامل باستثناء عناصر مصفوفة المستندات. الآن ، ليس علينا تعيين كل خاصية من JSON الواردة في نماذج البيانات الخاصة بنا. لنفترض أننا مهتمون فقط بحقلين من كائنات المقالات ، وهما Lead_paragraph و web_url . تعتبر فئة ArticleModel سهلة التنفيذ إلى حد ما ، كما نرى أدناه.
#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
الآن وقد تم تحديد نموذج المقالة ، يمكننا إنهاء تعريف نموذج الاستجابة عن طريق إنشاء نموذج لقائمة المقالات. إليك كيف سيبدو نموذج استجابة 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
هذه الفئة لها خاصيتان فقط: الحالة والمقالات . إذا قارناه بالاستجابة من نقطة النهاية ، فسنرى أنه لن يتم تعيين حقوق النشر الخاصة بسمة JSON الثالثة في نموذج الاستجابة. إذا نظرنا إلى طريقة articlesJSONTransformer ، فسنرى أنها تُرجع مُحَوِّلًا لقيمة مصفوفة تحتوي على كائنات من الفئة ArticleModel .
تجدر الإشارة أيضًا إلى أنه في طريقة JSONKeyPathsByPropertyKey ، تتوافق مقالات خصائص النموذج مع مستندات المصفوفة المتداخلة في استجابة سمة JSON.
الآن يجب أن يكون لدينا ثلاث فئات نموذجية مطبقة: ArticleListRequestModel و ArticleModel و ArticleListResponseModel.
أول طلب API
الآن وقد قمنا بتنفيذ جميع نماذج البيانات ، فقد حان الوقت للعودة إلى فئة APIManager لتنفيذ الطريقة التي سنستخدمها لتنفيذ طلبات GET إلى واجهة برمجة التطبيقات. طريقة:
- (NSURLSessionDataTask *) getArticlesWithRequestModel:(ArticleListRequestModel *)requestModel success:(void (^)(ArticleListResponseModel *responseModel))success failure:(void (^)(NSError *error))failure
يأخذ نموذج طلب ArticleListRequestModel كمعامل ويعيد ArticleListResponseModel في حالة النجاح أو خطأ NSE بطريقة أخرى. يستخدم تنفيذ هذه الطريقة AFNetworking لتنفيذ طلب GET لواجهة برمجة التطبيقات. يرجى ملاحظة أنه من أجل تقديم طلب ناجح لواجهة برمجة التطبيقات ، نحتاج إلى توفير مفتاح يمكن الحصول عليه كما ذكرنا سابقًا ، من خلال التسجيل في 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); }]; }
هناك شيئان مهمان للغاية يحدثان في تنفيذ هذه الطريقة. دعونا أولاً نلقي نظرة على هذا الخط:
NSDictionary *parameters = [MTLJSONAdapter JSONDictionaryFromModel:requestModel error:nil];
ما يحدث هنا هو أنه باستخدام الطريقة التي توفرها فئة MTLJSONAdapter ، نحصل على تمثيل NSD Dictionary لنموذج البيانات الخاص بنا. يعكس هذا التمثيل JSON الذي سيتم إرساله إلى API. هذا هو المكان الذي يكمن فيه جمال عباءة. بعد تنفيذ JSONKeyPathsByPropertyKey و +<propertyName>JSONTransformer
في فئة ArticleListRequestModel ، يمكننا الحصول على تمثيل JSON الصحيح لنموذج البيانات الخاص بنا في أي وقت من الأوقات باستخدام سطر واحد فقط من التعليمات البرمجية.
يسمح لنا Mantle أيضًا بإجراء تحويلات في الاتجاه الآخر أيضًا. وهذا بالضبط ما يحدث مع البيانات الواردة من API. تم تعيين قاموس NSD الذي نستلمه في كائن من فئة ArticleListResponseModel باستخدام طريقة الفئة التالية:
ArticleListResponseModel *list = [MTLJSONAdapter modelOfClass:ArticleListResponseModel.class fromJSONDictionary:responseDictionary error:&error];
استمرار البيانات مع المجال
الآن وقد أصبحنا قادرين على جلب البيانات من واجهة برمجة تطبيقات بعيدة ، فقد حان الوقت لاستمرارها. كما هو مذكور في المقدمة ، سنفعل ذلك باستخدام Realm. Realm هي قاعدة بيانات متنقلة وبديل للبيانات الأساسية و SQLite. كما سنرى أدناه ، إنه سهل الاستخدام للغاية.
لحفظ جزء من البيانات في Realm ، نحتاج أولاً إلى تغليف كائن مشتق من فئة RLMObject. ما يتعين علينا فعله الآن هو إنشاء فئة نموذجية تخزن البيانات لمقالات فردية. إليك مدى سهولة إنشاء مثل هذه الفئة.
#import "RLMObject.h" @interface ArticleRealm : RLMObject @property NSString *leadParagraph; @property NSString *url; @end
ويمكن أن يكون هذا في الأساس ، يمكن أن يظل تطبيق هذه الفئة فارغًا. يرجى ملاحظة أن الخصائص في فئة النموذج ليس لها سمات مثل nonatomic أو strong أو copy. تهتم المملكة بهؤلاء ولا داعي للقلق بشأنهم.
نظرًا لأن المقالات التي يمكننا الحصول عليها تم تصميمها باستخدام مقالة نموذج Mante ، فسيكون من الملائم تهيئة كائنات ArticleRealm بأشياء من فئة المقالة . للقيام بذلك سنضيف طريقة initWithMantleModel إلى نموذج Realm الخاص بنا. إليك التنفيذ الكامل لفئة 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
نتفاعل مع قاعدة البيانات باستخدام كائنات من فئة RLMRealm . يمكننا بسهولة الحصول على كائن RLMRealm من خلال استدعاء الطريقة "[RLMRealm defaultRealm]". من المهم أن تتذكر أن مثل هذا الكائن صالح فقط داخل مؤشر الترابط الذي تم إنشاؤه عليه ولا يمكن مشاركته عبر سلاسل الرسائل. تعد كتابة البيانات إلى Realm أمرًا سهلاً للغاية. كتابة واحدة ، أو سلسلة منها ، يجب أن تتم في صفقة كتابة. إليك نموذج للكتابة في قاعدة البيانات:
RLMRealm *realm = [RLMRealm defaultRealm]; ArticleRealm *articleRealm = [ArticleRealm new]; articleRealm.leadParagraph = @"abc"; articleRealm.url = @"sampleUrl"; [realm beginWriteTransaction]; [realm addObject:articleRealm]; [realm commitWriteTransaction];
ما يحدث هنا هو التالي. أولاً نقوم بإنشاء كائن RLMRealm للتفاعل مع قاعدة البيانات. ثم يتم إنشاء كائن نموذج ArticleRealm (يرجى الانتباه إلى أنه مشتق من فئة RLMRealm ). أخيرًا لحفظه ، تبدأ معاملة الكتابة ، ويضاف الكائن إلى قاعدة البيانات ، وبمجرد حفظه ، يتم تنفيذ معاملة الكتابة. كما نرى ، تؤدي كتابة المعاملات إلى حظر مؤشر الترابط الذي تم استدعاءها عليه. بينما يُقال إن Realm سريع جدًا ، إذا أردنا إضافة كائنات متعددة إلى قاعدة البيانات ضمن معاملة واحدة في الخيط الرئيسي ، فقد يؤدي ذلك إلى أن تصبح واجهة المستخدم غير مستجيبة حتى تنتهي المعاملة. الحل الطبيعي لذلك هو إجراء معاملة الكتابة على مؤشر ترابط في الخلفية.
طلب API والاستجابة المستمرة في العالم
هذه هي كل المعلومات التي نحتاجها لاستمرار المقالات باستخدام Realm. دعنا نحاول تنفيذ طلب API باستخدام الطريقة
- (NSURLSessionDataTask *) getArticlesWithRequestModel:(ArticleListRequestModel *)requestModel success:(void (^)(ArticleListResponseModel *responseModel))success failure:(void (^)(NSError *error))failure
ونماذج طلب واستجابة عباءة من أجل الحصول على مقالات New York Times التي لها علاقة (كما في المثال السابق) بكرة السلة وتم نشرها في الأيام السبعة الأولى من شهر يونيو 2015. بمجرد توفر قائمة بهذه المقالات ، سوف تستمر في المملكة. يوجد أدناه الكود الذي يقوم بذلك. يتم وضعها في طريقة viewDidLoad لوحدة تحكم عرض الجدول في تطبيقنا.
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]; }];
أولاً ، يتم إجراء استدعاء API (2) باستخدام نموذج طلب (1) ، والذي يقوم بإرجاع نموذج استجابة يحتوي على قائمة بالمقالات. من أجل الاستمرار في هذه المقالات باستخدام Realm ، نحتاج إلى إنشاء كائنات نموذج Realm ، والتي تحدث في حلقة for (4). من المهم أيضًا ملاحظة أنه نظرًا لاستمرار وجود كائنات متعددة في معاملة كتابة واحدة ، يتم تنفيذ معاملة الكتابة هذه على مؤشر ترابط في الخلفية (3). الآن ، بمجرد حفظ جميع المقالات في Realm ، نقوم بتخصيصها لخاصية الفصل self.articles (7). نظرًا لأنه سيتم الوصول إليها لاحقًا في الخيط الرئيسي في طرق مصدر بيانات TableView ، فمن الآمن استردادها من قاعدة بيانات Realm في السلسلة الرئيسية أيضًا (5). مرة أخرى ، للوصول إلى قاعدة البيانات من مؤشر ترابط جديد ، يجب إنشاء كائن RLMRealm جديد (6) في هذا الموضوع.
إذا فشل الحصول على مقالات جديدة من واجهة برمجة التطبيقات لأي سبب من الأسباب ، فسيتم استرداد المقالات الموجودة من التخزين المحلي في كتلة الفشل.
تغليف
في هذا البرنامج التعليمي ، تعلمنا كيفية تكوين Mantle ، وهو إطار نموذجي لـ Cocoa و Cocoa Touch ، من أجل التفاعل مع واجهة برمجة تطبيقات بعيدة. تعلمنا أيضًا كيفية استمرار البيانات المسترجعة محليًا في شكل كائنات نموذج Mantle باستخدام قاعدة بيانات Realm mobile.
في حالة رغبتك في تجربة هذا التطبيق ، يمكنك استرداد الكود المصدري من مستودع GitHub الخاص به. ستحتاج إلى إنشاء وتوفير مفتاح API الخاص بك قبل تشغيل التطبيق.