मार्वल नायकों को देखने के लिए हम RestKit 0.22.x का उपयोग करते हैं

वेब सेवाएं, विशेष रूप से REST आर्किटेक्चर का उपयोग करते हुए, पहले से ही हमारे जीवन में कसकर प्रवेश कर चुकी हैं। आईओएस के लिए एक क्लाइंट एप्लिकेशन विकसित करते समय, अक्सर एक ही रास्ता या कोई अन्य आपको सर्वर से डेटा डाउनलोड करना और उन्हें स्थानीय रूप से स्टोर / प्रदर्शित करना होता है। उसी समय, मैं अपने स्वयं के "साइकिल" के आविष्कार का सहारा लिए बिना, यह आसानी से और स्वाभाविक रूप से करना चाहता हूं।

IOS और OSX के लिए जाने-माने ऑब्जेक्टिव-सी रेस्टिट फ्रेमवर्क का नवीनतम संस्करण RESTful API के साथ काम को बहुत सरल करता है। निस्संदेह, इसकी सबसे मूल्यवान विशेषताओं में से एक कोरडाटा का उपयोग करके स्थानीय डेटाबेस में वस्तुओं को स्वचालित रूप से सहेजने की क्षमता है। आइए सर्वर से डेटा प्राप्त करने से लेकर उसे सहेजने और हमारे iOS डिवाइस पर प्रदर्शित करने तक का लंबा सफर तय करें। और इसलिए कि हम ऊब नहीं होंगे, एक उदाहरण के रूप में, हम विश्व प्रसिद्ध कॉमिक बुक कंपनी मार्वल के एपीआई के साथ काम करेंगे।

लेख एक तरह का ट्यूटोरियल है। यह माना जाता है कि पाठक पहले से ही आईओएस एसडीके, कोर डेटा और ब्लॉक जैसी अवधारणा का उपयोग करते हुए ऑब्जेक्टिव-सी में विकास की मूल अवधारणाओं से परिचित है।



1. चाबियाँ मार्वल प्राप्त करें और समस्या को तैयार करें


आरंभ करने के लिए, चलो मार्वल वेबसाइट पर एक डेवलपर के रूप में पंजीकरण करें।
तुच्छ पंजीकरण के बाद, खाता टैब पर जाएं और हमारी सार्वजनिक और निजी कुंजी की प्रतिलिपि बनाएँ।

उसके बाद, इंटरएक्टिव डॉक्यूमेंटेशन टैब पर जाएं और देखें कि एपीआई निर्माता किस तरह का डेटा हमें प्रदान करते हैं। हमारे पास नायकों, कॉमिक्स, रचनाकारों, घटनाओं और अधिक के डेटाबेस के साथ काम करने का अवसर है। परिचित होने के लिए, यह हमारे लिए एक बात को "स्पर्श" करने के लिए पर्याप्त होगा, इसलिए भविष्य का एप्लिकेशन केवल वर्णों की सूची डाउनलोड करेगा, इसे बचाएगा, और सबसे लोकप्रिय का विवरण भी प्रदर्शित करेगा।

2. आरंभ करना


Xcode में एक नया प्रोजेक्ट बनाएं। हम डिवाइस के रूप में iPhone का चयन करेंगे और प्रोजेक्ट प्रोजेक्ट विज़ार्ड विंडो में "कोर डेटा का उपयोग करें" फ़ील्ड के बगल में एक चेक मार्क छोड़ने के लिए मत भूलना।

अब पोर्टल पर वापस जाएं और Character ऑब्जेक्ट की संरचना पर विचार करें:
चरित्र वस्तु
 Character { id (int, optional): The unique ID of the character resource., name (string, optional): The name of the character., description (string, optional): A short bio or description of the character., modified (Date, optional): The date the resource was most recently modified., resourceURI (string, optional): The canonical URL identifier for this resource., urls (Array[Url], optional): A set of public web site URLs for the resource., thumbnail (Image, optional): The representative image for this character., comics (ComicList, optional): A resource list containing comics which feature this character., stories (StoryList, optional): A resource list of stories in which this character appears., events (EventList, optional): A resource list of events in which this character appears., series (SeriesList, optional): A resource list of series in which this character appears. } 
इनमें से हमें क्या चाहिए? शायद, हम खुद को पहचानकर्ता, नाम, चित्र और विवरण तक सीमित रखते हैं। आइए Xcode में अपनी * .xcdatamodeld फाइल पर चलते हैं और एक Character एंटिटी बनाते हैं जो तार्किक रूप से (आंशिक रूप से) हमारी दूरस्थ वस्तु के अनुरूप होगी।


मैंने जानबूझकर दो पहचानकर्ता बनाए हैं: पहला, charID , भविष्य के लिए "देशी मार्वल की" id को स्टोर करने का काम करेगा, जबकि दूसरे, innerID को स्थानीय उपयोग के लिए आवश्यक होगा। charDescription और नाम विशेषताएँ क्रमशः दूरस्थ मापदंडों के वर्णन और नाम के अनुरूप हैं।
ध्यान दें कि मैंने भी दो विशेषताएँ बनाईं, thumbnailImageData और thumbnailURLString , हालांकि वे मूल संरचना के किसी भी पैरामीटर से मेल नहीं खाते हैं। ऐसा इसलिए है क्योंकि JSON की प्रतिक्रिया में thumbnail प्रकार की Image वास्तव में शब्दकोश से मेल खाती है। यहाँ एक उदाहरण thumbnail वस्तु है जो वास्तविक उत्तर से है:
 "thumbnail": { "path": "http://i.annihil.us/u/prod/marvel/i/mg/8/c0/4ce5a0e31f109", "extension": "jpg" } 

भविष्य में, हम दिखाएंगे कि हम इसके साथ कैसे काम करेंगे।

अब, कोर डेटा संस्थाओं के साथ सही ढंग से काम करने के लिए, आपको एक ऑब्जेक्टिव-सी क्लास बनाने की भी ज़रूरत है जो इसका प्रतिनिधित्व करेगी। एक Character वर्ग बनाएँ जो NSManagedObject से इनहेरिट करेगा। यहाँ उसकी घोषणा है:
 @interface Character : NSManagedObject { NSDictionary *_thumbnailDictionary; } @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSNumber *charID; @property (nonatomic, retain) NSNumber *innerID; @property (nonatomic, retain) NSString *charDescription; @property (nonatomic, retain) NSData *thumbnailImageData; @property (nonatomic, retain) NSString *thumbnailURLString; @property NSDictionary *thumbnailDictionary; //       + (NSInteger)allCharsCountWithContext:(NSManagedObjectContext *)managedObjectContext; //     innerID. + (Character *)charWithManagedObjectContext:(NSManagedObjectContext *)context andInnerID:(NSInteger)charInnerID; @end 

यहाँ, स्पष्ट अनुरूपताओं के अलावा, thumbnailDictionary प्रॉपर्टी दिखाई दी, जिसे मैंने थंबनेल ऑब्जेक्ट के साथ अधिक सुविधाजनक काम के लिए जोड़ा, जिसके बारे में मैंने थोड़ा ऊपर लिखा था। मैंने दो हेल्पर क्लास के तरीके भी जोड़े ताकि प्रोजेक्ट में अतिरिक्त कक्षाएं न बनाई जा सकें।

3. RestKit के साथ काम करने के लिए मॉडल


हमारे प्रोजेक्ट रेस्टकिट (इसके बाद - आरके) से कनेक्ट करें। यह कैसे किया जाता है यह यहाँ विस्तृत है (या यदि आप एक कोकोआ प्रेमी हैं)।

अगला कदम एक रैपर क्लास GDMarvelRKObjectManager ( NSObject ) बनाना होगा जो RK के साथ विशेष रूप से RKObjectManager और RKManagedObjectStore जैसी कक्षाओं के साथ काम करेगा। यह वर्ग नहीं बनाया जा सकता है, लेकिन हम इसे अपने भविष्य के मुख्य दृश्य नियंत्रक में कोड को थोड़ा सा लोड करने के लिए जाएंगे।

आरके वर्गों के बारे में थोड़ा। RKManagedObjectStore कोर डेटा के साथ सभी काम को RKManagedObjectStore करता है, ताकि भविष्य में सीधे NSManagedObjectContext या NSManagedObjectModel साथ काम करने की आवश्यकता न हो। RKObjectManager वस्तुओं के मानचित्रण (मिलान) का उपयोग करके अनुरोध भेजने और प्रतिक्रिया प्राप्त करने के लिए एक केंद्रीकृत इंटरफ़ेस प्रदान करता है। उदाहरण के लिए, JSON प्रतिक्रिया में प्राप्त आवश्यक मान, सफल मानचित्रण पर, स्वचालित रूप से हमारी वस्तु के सभी गुणों को सौंपा जाएगा। क्या यह नहीं है कि हम लेख की शुरुआत में क्या चाहते थे?
अपनी * .h फ़ाइल में RK #import <RestKit/RestKit.h>
हमारे आवरण वर्ग में गुण नहीं होंगे, लेकिन इसके दो उदाहरण चर होंगे:
 @implementation GDMarvelRKObjectManager { RKObjectManager *objectManager; RKManagedObjectStore *managedObjectStore; } 

आइए देखें कि हमें क्या कॉन्फ़िगर करने की आवश्यकता है ताकि सब कुछ उसी तरह काम करे जैसा कि इसे करना चाहिए।
सबसे पहले, - (id)init विधि में, आवश्यक आरके ऑब्जेक्ट्स के आरंभीकरण को जोड़ें:
 //  AFNetworking HTTPClient NSURL *baseURL = [NSURL URLWithString:@"http://gateway.marvel.com/"]; AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL]; // RKObjectManager objectManager = [[RKObjectManager alloc] initWithHTTPClient:client]; 

अब हमारे अनुरोध भेजे जाएंगे। कोर डेटा के साथ काम करने के बारे में क्या? आइए एक विधि बनाते हैं जो RKManagedObjectStore प्रकार का ऑब्जेक्ट कॉन्फ़िगर करता है।
 - (void)configureWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel { if (!managedObjectModel) return; managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; NSError *error; if (!RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error)) RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"RKMarvel.sqlite"]; if (![managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]) RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); [managedObjectStore createManagedObjectContexts]; objectManager.managedObjectStore = managedObjectStore; } 

अंतिम पंक्ति बहुत महत्वपूर्ण है। यह हमारी दो मुख्य आरके वस्तुओं को एक साथ जोड़ता है: objectManager और objectManager

इसलिए, हमारा आगे का काम दो मुख्य क्रियाओं के लिए हमारे GDMarvelRKObjectManager वर्ग में एक इंटरफ़ेस बनाना है: कोर डेटा इकाई और दूरस्थ ऑब्जेक्ट के बीच मैपिंग (पत्राचार) जोड़ना, साथ ही रिमोट सर्वर से इन ऑब्जेक्ट्स को प्राप्त करना।
पहला कार्य निम्नलिखित विधि में लागू किया गया है:
 - (void)addMappingForEntityForName:(NSString *)entityName andAttributeMappingsFromDictionary:(NSDictionary *)attributeMappings andIdentificationAttributes:(NSArray *)ids andPathPattern:(NSString *)pathPattern { if (!managedObjectStore) return; RKEntityMapping *objectMapping = [RKEntityMapping mappingForEntityForName:entityName inManagedObjectStore:managedObjectStore]; // ,    . [objectMapping addAttributeMappingsFromDictionary:attributeMappings]; // ,    .   ,       . objectMapping.identificationAttributes = ids; //   ,           . RKResponseDescriptor *characterResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:objectMapping method:RKRequestMethodGET pathPattern:[NSString stringWithFormat:@"%@%@", MARVEL_API_PATH_PATTERN, pathPattern] keyPath:@"data.results" statusCodes:[NSIndexSet indexSetWithIndex:200]]; [objectManager addResponseDescriptor:characterResponseDescriptor]; } 


यहाँ हम responseDescriptorWithMapping:... विधि के कई मापदंडों में रुचि रखते हैं responseDescriptorWithMapping:... सबसे पहले, pathPattern पैरामीटर। मैक्रो MARVEL_API_PATH_PATTERN (मान @"v1/public/" ) और इनपुट पैरामीटर pathPattern , जो हमारे उदाहरण में @"characters" । यदि हम वर्णों की सूची नहीं प्राप्त करना चाहते हैं, लेकिन कहते हैं, कॉमिक्स की एक सूची है, तो हम लाइन @”comics” पास करेंगे, जो पहले से ही विधि के शरीर में फिर से @"v1/public/" जुड़ा होगा।
दूसरा गैर-स्पष्ट मान @"data.results" पैरामीटर के लिए @"data.results" पैरामीटर है। यह कहां से आया? सब कुछ बहुत सरल है: मार्वल ने एक ही आवरण में अपने सभी उत्तरों को लपेट दिया, और जब हम इसकी संरचना को देखते हैं तो सब कुछ ठीक हो जाएगा:
वर्ण आवरण
 { "code": "int", "status": "string", "copyright": "string", "attributionText": "string", "attributionHTML": "string", "data": { "offset": "int", "limit": "int", "total": "int", "count": "int", "results": [ { "id": "int", "name": "string", "description": "string", "modified": "Date", "resourceURI": "string", "urls": [ { "type": "string", "url": "string" } ], "thumbnail": { "path": "string", "extension": "string" }, "comics": { "available": "int", "returned": "int", "collectionURI": "string", "items": [ { "resourceURI": "string", "name": "string" } ] }, "stories": { "available": "int", "returned": "int", "collectionURI": "string", "items": [ { "resourceURI": "string", "name": "string", "type": "string" } ] }, "events": { "available": "int", "returned": "int", "collectionURI": "string", "items": [ { "resourceURI": "string", "name": "string" } ] }, "series": { "available": "int", "returned": "int", "collectionURI": "string", "items": [ { "resourceURI": "string", "name": "string" } ] } } ] }, "etag": "string" } 

अब यह स्पष्ट है कि नायकों की वास्तविक सूची तक पहुंचने से पहले, आरके को वांछित संरचना प्राप्त करने के लिए कई स्तरों के शब्दकोशों से गुजरना होगा। मान @"data.results" केवल उस पथ को इंगित करता है जिसके साथ आपको "नीचे जाने" की आवश्यकता होती है।

आंतरिक आरके ऑब्जेक्ट के साथ काम करने के लिए हमारी कक्षा का दूसरा तरीका getMarvelObjectsAtPath होगा, जो अनिवार्य रूप से getObjectsAtPath ऑब्जेक्ट के getObjectsAtPath को कॉल प्रॉक्सी करता है। विधि का नाम "बात करना" है - आप इसे हटाए गए ऑब्जेक्ट्स के लोडिंग से उम्मीद करते हैं। चूँकि मार्वल को उस हैश, टाइमस्टैम्प और एक सार्वजनिक कुंजी को प्रत्येक अनुरोध के साथ उनके पास भेजा जाना आवश्यक है, इसलिए हमारे getMarvelObjectsAtPath में इन मापदंडों की पीढ़ी को इनकैप्सुलेट करना सुविधाजनक है। यहाँ यह है:
 - (void)getMarvelObjectsAtPath:(NSString *)path parameters:(NSDictionary *)params success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure { //    NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyyMMddHHmmss"]; NSString *timeStampString = [formatter stringFromDate:[NSDate date]]; NSString *hash = [[[NSString stringWithFormat:@"%@%@%@", timeStampString, MARVEL_PRIVATE_KEY, MARVEL_PUBLIC_KEY] MD5String] lowercaseString]; NSMutableDictionary *queryParams = [NSMutableDictionary dictionaryWithDictionary:@{@"apikey" : MARVEL_PUBLIC_KEY, @"ts" : timeStampString, @"hash" : hash}]; if (params) [queryParams addEntriesFromDictionary:params]; //      objectManager     [objectManager getObjectsAtPath:[NSString stringWithFormat:@"%@%@", MARVEL_API_PATH_PATTERN, path] parameters:queryParams success:success failure:failure]; } 

कृपया ध्यान दें कि कोड NSString - MD5String ऊपर गैर-मानक श्रेणी से एक विधि का उपयोग करता है। एक लाइन से एमडी 5-ट्रंक कैसे उत्पन्न करें, इंटरनेट पर देखें
हमारी कक्षा में अभी भी एक सरल विधि होगी - (NSManagedObjectContext *)managedObjectContext , जो - (NSManagedObjectContext *)managedObjectContext के मुख्य संदर्भ को लौटाएगा। इसके अलावा, यह वर्ग उदाहरण के लिए एक्सेस करने के लिए + (GDMarvelRKObjectManager *)manager विधि के साथ एक ( सिंगलटन ) सिंगलटन होगा।

4. मुख्य दृश्य नियंत्रक


इसके GDBaseViewController शुरू करने के लिए, हम एक बुनियादी GDBaseViewController नियंत्रक GDBaseViewController जिसमें हम केवल नई विधि के साथ सर्वर से प्रतिक्रिया के लिए एनिमेटेड प्रतीक्षा के लिए समर्थन को एकीकृत करते हैं - (void)animateActivityIndicator:(BOOL)animateviewDidLoad विधि में viewDidLoad UIActivityIndicatorView प्रकार का यह संकेतक बनाएं, उदाहरण के लिए प्राप्त मान को UIActivityIndicatorView *activityIndicator असाइन करें UIActivityIndicatorView *activityIndicator और इसे self.view जोड़ें।
एनीमेशन ऑन / ऑफ विधि में, निम्न कोड होगा:
animateActivityIndicator: कोड
 - (void)animateActivityIndicator:(BOOL)animate { activityIndicator.hidden = !animate; if (animate) { [self.view bringSubviewToFront:activityIndicator]; [activityIndicator startAnimating]; } else [activityIndicator stopAnimating]; } 

अब, जब हम किसी एकल पैरामीटर के लिए YES मान के साथ इस विधि को कहते हैं, तो हमारा दृश्य नियंत्रक इस तरह दिखाई देगा:


अगला, इस वर्ग से विरासत में मिला GDMainViewController एक GDMainViewController नियंत्रक GDMainViewController । यहाँ उसकी घोषणा है:
 @interface GDMainViewController : GDBaseViewController <UITableViewDataSource, UITableViewDelegate, UIAlertViewDelegate> { UITableView *table; NSInteger numberOfCharacters; AllAroundPullView *bottomPullView; BOOL noRequestsMade; } @end 

इस दृश्य नियंत्रक में, हम डेटाबेस से डेटा प्रदर्शित करेंगे। ऐसा करने के लिए, हम UITableView उदाहरण का उपयोग करेंगे, जिस पर प्रत्येक कक्ष में एक चित्र और प्रत्येक वर्ण का नाम प्रदर्शित किया गया है। लेकिन उन्हें अभी भी डाउनलोड करने की आवश्यकता है, क्योंकि शुरू में स्थानीय डेटाबेस खाली है। UITableView उदाहरण बनाने में निहित सभी आरंभिक प्रक्रिया के बाद - (void)viewDidLoad , हम सबसे पहले अपने CoreData मॉडल को RKManagedObjectStore हमारे GDMarvelRKObjectManager रैपर GDMarvelRKObjectManager का उपयोग करके GDMarvelRKObjectManager :
 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Marvel" withExtension:@"momd"]; [[GDMarvelRKObjectManager manager] configureWithManagedObjectModel:[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]]; //        Character: [[GDMarvelRKObjectManager manager] addMappingForEntityForName:@"Character" andAttributeMappingsFromDictionary:@{ @"name" : @"name", @"id" : @"charID", @"thumbnail" : @"thumbnailDictionary", @"description" : @"charDescription" } andIdentificationAttributes:@[@"charID"] andPathPattern:MARVEL_API_CHARACTERS_PATH_PATTERN]; 

जैसा कि आप देख सकते हैं, एक शब्दकोश जिसमें दूरस्थ वस्तु के JSON कुंजियों के नाम के बीच पत्राचार शामिल है और हमारे द्वारा बनाए गए वर्ग के गुणों को andAttributeMappingsFromDictionary: पैरामीटर के रूप में पारित किया गया है। जैसा कि andPathPattern: पैरामीटर, स्ट्रिंग @"characters" पारित किया गया है (मैक्रो MARVEL_API_CHARACTERS_PATH_PATTERN ) - दूरस्थ JSON ऑब्जेक्ट का नाम।

हमने मैपिंग को जोड़ने के बाद, [self loadCharacters] विधि को कॉल किया।
विस्तार से विचार करें कि वह क्या करता है:
 - (void)loadCharacters { numberOfCharacters = [Character allCharsCountWithContext:[[GDMarvelRKObjectManager manager] managedObjectContext]]; if (noRequestsMade && numberOfCharacters > 0) { noRequestsMade = NO; return; } [self animateActivityIndicator:YES]; noRequestsMade = NO; [[GDMarvelRKObjectManager manager] getMarvelObjectsAtPath:MARVEL_API_CHARACTERS_PATH_PATTERN parameters:@{@"offset" : @(numberOfCharacters)} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { [self animateActivityIndicator:NO]; NSInteger newInnerID = numberOfCharacters; for (Character *curCharacter in mappingResult.array) { if ([curCharacter isKindOfClass:[Character class]]) { curCharacter.innerID = @(newInnerID); newInnerID++; //     (     ),   ,        [self saveToStore]; } } numberOfCharacters = newInnerID; [table reloadData]; bottomPullView.hidden = NO; [bottomPullView finishedLoading]; } failure:^(RKObjectRequestOperation *operation, NSError *error) { [bottomPullView finishedLoading]; [[[UIAlertView alloc] initWithTitle:@"Marvel API Error" message:operation.error.localizedDescription delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Retry", nil] show]; }]; } 

सबसे पहले, हमें स्थानीय डेटाबेस से कुल वर्ण मिलते हैं, यह मान मुख्य तालिका में कोशिकाओं की संख्या के अनुरूप होगा। जब आप पहली बार आवेदन शुरू करते हैं, तो यह निश्चित रूप से शून्य होगा। सर्वर का उपयोग करते समय हम प्रेषित ऑफसेट पैरामीटर के समान मूल्य का उपयोग करेंगे। इस प्रकार, प्रत्येक बाद के अनुरोध के लिए, मार्वल सर्वर केवल नए हीरो ऑब्जेक्ट्स लौटाएगा (डिफ़ॉल्ट रूप से, नायक प्रत्येक 20 टुकड़े के पैक लौटाते हैं)।
अगला, हम अपने getMarvelObjectsAtPath आवरण getMarvelObjectsAtPath का उपयोग करके एक ही मुख्य अनुरोध करते हैं:
इस पद्धति के दो पैरामीटर हैं जो अभी हमारे लिए महत्वपूर्ण हैं - ये सफलता हैं: और विफलता:, जो ब्लॉक हैं जो क्रमशः क्वेरी निष्पादन के सफल और असफल परिणामों के व्यवहार का वर्णन करते हैं। इसलिए, वर्णों की एक सरणी की सफल प्राप्ति पर, हम उनमें से प्रत्येक के लिए एक innerID उत्पन्न करते हैं, उन्हें स्थानीय डेटाबेस में सहेजते हैं और वर्णों की कुल संख्या के मूल्य को बदलते हैं। फिर हमारी तालिका का प्रदर्शन अपडेट करें। यहां मुख्य जादू यह है कि इस स्तर पर, प्राप्त वस्तुओं को पहले से ही हमारे कोरडेटा भंडारण में स्वचालित रूप से सहेजा जाता है - आरके ने हमारे लिए किया। (यह ध्यान देने योग्य है कि यह केवल उस ऑब्जेक्ट के फ़ील्ड्स / गुणों पर लागू होता है जिसके लिए मैपिंग मैच निर्दिष्ट होते हैं। इसलिए, ऊपर दिए गए कोड में, innerID [self saveToStore] कहकर innerID पैरामीटर के परिवर्तन को अलग से सहेजना होगा।
त्रुटि की स्थिति में, हम इसे केवल उपयोगकर्ता को प्रदर्शित करते हैं और तालिका को अपडेट नहीं करते हैं।

कोड संग्रहण विधि का उपयोग करता है:
 - (void)saveToStore { NSError *saveError; if (![[[GDMarvelRKObjectManager manager] managedObjectContext] saveToPersistentStore:&saveError]) XLog(@"%@", [saveError localizedDescription]); } 

आप bottomPullView उदाहरण bottomPullView संदर्भ भी देखेंगे। यह वैरिएबल AllAroundPullView ( GitHub से खींचा गया ) प्रकार की एक वस्तु को संग्रहीत करता है - एक उपयोगी नियंत्रण जो आपके UIScrollView सभी पक्षों से Pull-To-Resfresh व्यवहार को लागू करने में मदद करता है। हम अपने पात्रों के प्रत्येक अगले हिस्से को लोड करेंगे, तालिका के निचले किनारे तक पहुंचेंगे और इसे ऊपर खींच लेंगे।
इससे पहले - (void)viewDidLoad इस नियंत्रण को प्रारंभ किया गया था और निम्नानुसार उपयोग किया गया था:
 bottomPullView = [[AllAroundPullView alloc] initWithScrollView:table position:AllAroundPullViewPositionBottom action:^(AllAroundPullView *view){ [self loadCharacters]; }]; bottomPullView.hidden = YES; [table addSubview:bottomPullView]; 

जैसा कि आप देख सकते हैं, पैरामीटर कार्रवाई के रूप में पारित ब्लॉक के शरीर में: हम नए नायकों को लोड करने वाले को लोड करने के लिए एक ही विधि loadCharacters

खैर, एमुलेटर में एप्लिकेशन को चलाएं और पहले सफल उत्तर की प्रतीक्षा करें। यदि सबकुछ सही हो गया, और आरके I restkit.network:RKObjectRequestOperation.m:220 GET 'http://your-url.here' (200 OK / 20 objects) ने I restkit.network:RKObjectRequestOperation.m:220 GET 'http://your-url.here' (200 OK / 20 objects) कुछ ऐसा I restkit.network:RKObjectRequestOperation.m:220 GET 'http://your-url.here' (200 OK / 20 objects) जो I restkit.network:RKObjectRequestOperation.m:220 GET 'http://your-url.here' (200 OK / 20 objects) , तो सब कुछ ठीक है, और आप जांच सकते हैं क्या हमारी वस्तुएं आधार में संरक्षित हैं।
ऐसा करने के लिए, एमुलेटर फ़ोल्डर पर जाएं, वहां हमारे एप्लिकेशन और दस्तावेज़ फ़ोल्डर को ढूंढें। RKMarvel.sqlite बेस RKMarvel.sqlite होना चाहिए (यह वह नाम है जिसे हमने एक पैरामीटर के रूप में निर्दिष्ट किया है जब addSQLitePersistentStoreAtPath: विधि पहले)। इस आधार को SQLite- संपादक में खोलें और सुनिश्चित करें कि हमारे अक्षर सहेजे गए हैं:

हुर्रे! कुछ नायकों का एक छोटा वर्णन भी है। यह सब "अच्छा" प्रदर्शित करने के लिए जाने का समय है।

5. चित्रों और प्रदर्शन को सहेजना।


मुझे पता है कि एक अधीर पाठक लंबे समय से अपने पसंदीदा पात्रों की छवियों को देखना चाहता था। ऐसा करने के लिए, हमें अपनी तालिका के रूप को अनुकूलित करना होगा। हम UITableView प्रकार की वस्तुओं को बनाने और स्थापित करने के तकनीकी विवरण में नहीं जाएंगे (लेखक मानता है कि पाठक यह पहले से ही जानता है), लेकिन हम तुरंत कोशिकाओं को बनाने वाली तालिका के प्रतिनिधि विधि को पारित करेंगे:
tableView: cellForRowAtIndexPath: कोड
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSInteger row = indexPath.row; NSString *reusableIdentifier = [NSString stringWithFormat:@"%d", row % 2]; UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:reusableIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reusableIdentifier]; cell.autoresizingMask = UIViewAutoresizingFlexibleWidth; } [[cell.contentView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; if (numberOfCharacters > row) { Character *curCharacter = [Character charWithManagedObjectContext: [[GDMarvelRKObjectManager manager] managedObjectContext] andInnerID:row]; if (curCharacter) { BOOL charHasDescription = ![curCharacter.charDescription isEqualToString:@""]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(70, 0, CGRectGetWidth(cell.contentView.frame) - 70 - (charHasDescription ? 60 : 0), 60)]; label.backgroundColor = [UIColor clearColor]; label.text = curCharacter.name; label.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell.contentView addSubview:label]; GDCellThumbnailView *thumbnail = [GDCellThumbnailView thumbnail]; if (curCharacter.thumbnailImageData) [thumbnail setImage:[UIImage imageWithData:curCharacter.thumbnailImageData]]; else [self loadThumbnail:thumbnail fromURLString:curCharacter.thumbnailURLString forCharacter:curCharacter]; [cell.contentView addSubview:thumbnail]; cell.accessoryType = charHasDescription ? UITableViewCellAccessoryDetailButton : UITableViewCellSelectionStyleNone; cell.selectionStyle = charHasDescription ? UITableViewCellSelectionStyleGray : UITableViewCellSelectionStyleNone; } } return cell; } 

अगली सेल बनाने के बाद, हम डेटाबेस से वांछित हीरो प्राप्त करते हैं और उसका नाम प्रदर्शित करते हैं, हम यह भी जांचते हैं कि क्या उसके बारे में विस्तृत जानकारी है, और सेल पर एक बटन लगाएं, जिस पर क्लिक करके हम इस जानकारी को प्रदर्शित करेंगे। अच्छी तरह से और सबसे महत्वपूर्ण बात - चरित्र की छवि। इसके लिए मैंने एक विशेष वर्ग GDCellThumbnailView बनाया, जिसके उदाहरण मैंने सेल पर रखे थे। यह कुछ खास नहीं करता है, यह सिर्फ थम्बनेल लोड होने तक हमें "कताई फूल" दिखाने की क्षमता रखता है।

यदि loadThumbnail:fromURLString:forCharacter: विधि खाली है, तो हमारा मुख्य दृश्य नियंत्रक अब इस पर दिखेगा:


आइए नायक के चित्र को लोड करने के लिए एक विधि लागू करें। चूंकि RK में पहले से ही AFNetworking फ्रेमवर्क शामिल है, हम चित्रों का उपयोग करने के लिए मार्वल सर्वरों के लिए एक अतुल्यकालिक अनुरोध भेजने के लिए इसका उपयोग करेंगे:
 - (void)loadThumbnail:(GDCellThumbnailView *)view fromURLString:(NSString *)urlString forCharacter:(Character *)character { XLog(@"Loading thumbnail for %@", character.name); AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { character.thumbnailImageData = responseObject; [self saveToStore]; [view setImage:[UIImage imageWithData:responseObject]]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { XLog(@"%@", [error localizedDescription]); }]; [operation start]; } 

वह सब है। हमारे एप्लिकेशन को फिर से लॉन्च करें। पहले से ही एक अच्छा परिणाम है।


अब इसे रोकना मुश्किल होगा, और आपकी अनुमति से, मैं अधिक पात्रों को लोड करने के लिए सुविधाजनक पुल-टू-रिफ्रेश नियंत्रण का उपयोग करता हूं। उसी समय, हम जांच करेंगे कि हमारा आधार अब कैसा दिखता है।

अब दोनों चित्रों और नायकों के बारे में जानकारी (ज़ाहिर है, केवल जिन्हें हम डाउनलोड करने में कामयाब रहे हैं) स्थानीय स्तर पर संग्रहीत किए जाएंगे, भले ही हमारे पास इंटरनेट कनेक्शन हो या न हो।

6. निष्कर्ष।


RestKit पूरी तरह से कार्य के साथ सामना किया: अनुरोध भेजा जाता है, प्रतिक्रियाएं प्राप्त होती हैं, ऑब्जेक्ट स्वचालित रूप से सहेजे जाते हैं। हर कोई लोडिंग और प्रदर्शित करने के बहुत सिद्धांत को पसंद नहीं कर सकता है, इस लेख में प्रदान किया गया है: यह संभव है कि यह पूरे डेटाबेस को तुरंत अपवित्र करने और इसके साथ स्थानीय रूप से पूरी तरह से काम करने के लिए अधिक उचित होगा। लेखक का मानना ​​है कि आरके की बुनियादी क्षमताओं से परिचित होने के लिए, ऐसी कार्यक्षमता पर्याप्त है। पूरे प्रोजेक्ट का स्रोत कोड (इस आलेख में गायब भाग के साथ एक विशिष्ट चरित्र के बारे में जानकारी प्रदर्शित करता है) को GitHub पर डाउनलोड किया जा सकता है । आपकी इच्छाओं और टिप्पणियों का लेख पर टिप्पणियों के रूप में स्वागत किया जाता है, साथ ही गिटहब पर पूल अनुरोध भी।
अंत में, मैं एक और छवि को खुश करना चाहूंगा - इस बार यह दूसरे दृश्य नियंत्रक का स्क्रीनशॉट है, जो मुख्य दृश्य नियंत्रक में नायक के नाम के आगे "जानकारी" बटन पर क्लिक करके खुलता है। अंत में इसे लोड करने के लिए बहुत लंबे समय तक मैंने अपनी तालिका को स्क्रॉल किया:

Source: https://habr.com/ru/post/In220885/


All Articles