2012-03-01 12 views
17

मैं उस एप्लिकेशन के लिए RestKit का उपयोग करना चाहता हूं जिसे ऑन और ऑफ़लाइन दोनों काम करने की आवश्यकता है।RestKit आईओएस अनुप्रयोगों के लिए ऑनलाइन और ऑफ़लाइन समर्थन

मुझे गलत समझ हो सकती है कि रेस्टकिट कैसे काम करता है, लेकिन मैंने सोचा कि यह लागू करने के लिए (काफी) आसान था।

मैं चीजों को सेट अप के रूप में एक खरोंच परीक्षण iOS एप्लिकेशन में इस प्रकार है: के रूप में CoreData समर्थन के लिए आवश्यक

// setup the client 
NSString* URL = @"http://10.211.55.5:3000/api"; 
RKClient* client = [RKClient clientWithBaseURL:URL]; 
client.username = @"[email protected]"; 
client.password = @"password"; 

// setup caching 
client.cachePolicy = RKRequestCachePolicyLoadIfOffline | RKRequestCachePolicyLoadOnError | RKRequestCachePolicyTimeout; 
client.requestCache.storagePolicy = RKRequestCacheStoragePolicyPermanently; 

// setup managed object store 
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:URL]; 
RKManagedObjectStore* objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@"RestKitCoreDataTest.sqlite"]; 

// connect my cache implementation 
MyCache* cache = [[MyCache alloc] init]; 
objectStore.managedObjectCache = cache; 
objectManager.objectStore = objectStore; 

// setup mapping  
RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class]]; 
[userMapping mapKeyPath:@"id" toAttribute:@"identifier"]; 
[userMapping mapKeyPath:@"email" toAttribute:@"email"]; 
[userMapping mapKeyPath:@"firstname" toAttribute:@"firstname"]; 
[userMapping mapKeyPath:@"surname" toAttribute:@"surname"]; 
userMapping.primaryKeyAttribute = @"identifier"; 
[objectManager.mappingProvider setMapping:userMapping forKeyPath:@""]; 

// setup routes 
RKObjectRouter* router = [objectManager router]; 
[router routeClass:[User class] toResourcePath:@"https://stackoverflow.com/users/:identifier"]; 

उपयोगकर्ता वस्तु कार्यान्वित किया जाता है:

@interface User : NSManagedObject 

@property (nonatomic, retain) NSNumber * identifier; 
@property (nonatomic, retain) NSString * email; 
@property (nonatomic, retain) NSString * firstname; 
@property (nonatomic, retain) NSString * surname; 

@end 

@implementation User 

@dynamic identifier; 
@dynamic email; 
@dynamic firstname; 
@dynamic surname; 

@end 

यहाँ MyCache है। ध्यान दें कि मैं resourcePath की जांच करने के लिए परेशान नहीं हूं क्योंकि यह केवल चीजों की कोशिश करने के लिए है, और मेरे पास एक रास्ता है।

@implementation MyCache 
- (NSArray*)fetchRequestsForResourcePath:(NSString*)resourcePath 
{ 
    NSFetchRequest* fetchRequest = [User fetchRequest]; 
    return [NSArray arrayWithObject:fetchRequest]; 
} 

-(BOOL)shouldDeleteOrphanedObject:(NSManagedObject *)managedObject 
{ 
    return true; 
} 
@end 

मैं तो पथ "/ API/उपयोगकर्ताओं/123" में, सर्वर के लिए एक कॉल आईडी 123 के साथ उपयोगकर्ता पाने के लिए करते हैं:

User* user = [User object]; 
user.identifier = [NSNumber numberWithInt:123]; 
RKObjectManager* manager = [RKObjectManager sharedManager]; 
[manager getObject:user delegate:self]; 

यह ठीक काम करता है। लेकिन, जब मैं अपने मैक पर वाईफाई को डिस्कनेक्ट करता हूं, तो उपरोक्त कोड उपयोगकर्ता को SQLite डेटाबेस से पुनर्प्राप्त नहीं करता है।

2012-03-01 11:44:09.402 RestKitCoreDataTest[1989:fb03] error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo=0x6b89aa0 {NSErrorFailingURLStringKey=http://10.211.55.5:3000/api/users/123, NSErrorFailingURLKey=http://10.211.55.5:3000/api/users/123, NSLocalizedDescription=The request timed out., NSUnderlyingError=0x6b81ac0 "The request timed out."} 

मैंने सोचा था कि निर्दिष्ट करने कैश जब वहाँ के साथ एक समय समाप्ति है, इस्तेमाल किया जाना चाहिए कि के आधार पर: "RKRequestCachePolicyTimeout", मैं उम्मीद है |

मैं बजाय में प्रतिनिधि के objectLoader:didFailWithError निम्नलिखित त्रुटि मिलती है स्थानीय कैश से उपयोगकर्ता को पुनर्प्राप्त किया जाएगा।

कैश में Z 123ER के साथ उपयोगकर्ता रिकॉर्ड होता है - ZUSER तालिका में, ZIDENTIFIER कॉलम में 123 के साथ।

क्या कोई ऐसा कदम है जिसे मैं काम करने के लिए याद कर रहा हूं? हो सकता है कि को टाइमआउट के बाद कैश मारा जाता है, तो को संभालने की आवश्यकता है या कहा जाता है? या क्या मैं ऐसा कुछ करने की कोशिश कर रहा हूं जो आवश्यक नहीं है जिसे आप "बॉक्स से बाहर" प्राप्त कर सकें?

चीयर्स।

+0

हाय , मैं RestKit 0.20.1 के साथ ऐसा करने की कोशिश कर रहा हूं - इस पर कोई अपडेट? क्या आपको यह काम मिल गया? आपके द्वारा चेक किया गया उत्तर आपके प्रश्न का उत्तर नहीं देता है ... धन्यवाद! – Diego

+1

मैंने नीचे दिए गए उत्तर को सही के रूप में चेक किया क्योंकि मैंने जूलियन के एक पहुंच योग्यता वर्ग का उपयोग करने का सुझाव लिया ताकि यह जांच सके कि मैं ऑनलाइन या ऑफ़लाइन था या नहीं। बाद में मैंने ऑनलाइन संचार के लिए रेस्टकिट का उपयोग करके समाप्त किया, और कोरडाटा स्वयं ऑफ़लाइन स्टोरेज के लिए समाप्त हो गया। – dbarros

+0

ठीक है धन्यवाद! मुझे लगता है कि मैं इसे एपडिलेगेट में केंद्रीकृत करने की कोशिश करूंगा - हालांकि ऐसा करने के लिए मुझे लगता है कि अगर मैं एक HTTP ऑपरेशन कतार बनाता हूं तो बेहतर होता है कि मैं हर बार सिंक की आवश्यकता होती है (संभवतः समय-समय पर)। – Diego

उत्तर

6

आप अपने क्लाइंट ऑफ़लाइन है या नहीं, यह निर्धारित करने के लिए आप रीचैबिलिटी क्लास का उपयोग कर सकते हैं। मैं इस महान वर्ग का उपयोग हर परियोजना में अक्सर करता हूं जिसके लिए इंटरनेट कनेक्शन की आवश्यकता होती है।

आप बस एक विशिष्ट होस्ट के लिए नोटिफ़ायर प्रारंभ करते हैं। आपके सभी दृश्य नियंत्रक में अब आपको BOOL isOnline सेट करने के लिए बस NSNotificationCenter पर विधियों को पंजीकृत करना होगा।

इस अभ्यास को करने से आप अपने ऐप में सुंदर चीजें कर सकते हैं जैसे ऐप को एक चिकनी "ऑफलाइन" संदेश के साथ ओवरले करना।

https://gist.github.com/1182373

संपादित

एक उदाहरण यहाँ मेरा परियोजनाओं में से एक से प्रवेश स्क्रीन से

(कोड के इस मात्रा के लिए खेद है, लेकिन इस मेरा पूरा कार्यान्वयन है):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    //// Some stuff //// 
    [[Reachability reachabilityWithHostname:@"apple.com"] startNotifier]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil]; 
} 
- (void)reachabilityChanged:(NSNotification *)note 
{ 
    if ([[note object] isReachable]) { 
     CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; 
     [scale setValues:[NSArray arrayWithObjects:[NSNumber numberWithFloat:1.0], [NSNumber numberWithFloat:0.0], nil]]; 
     [scale setDuration:0.3]; 
     [scale setRemovedOnCompletion:NO]; 

     [[offlineView layer] setTransform:CATransform3DMakeScale(0, 0, 1.0)]; 
     [[offlineView layer] addAnimation:scale forKey:@"scale"]; 
     [[offlineView layer] setTransform:CATransform3DIdentity]; 

     [UIView animateWithDuration:0.3 animations:^{ 
      [offlineView setAlpha:0]; 
     } completion:^(BOOL finished){ 
      if (finished) { 
       [offlineView removeFromSuperview]; 
      } 
     }]; 

     [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES]; 
    } 
    else { 
     CGRect screenFrame = CGRectMake(0, 0, 320, 480); 

     offlineView = [[UIView alloc] initWithFrame:screenFrame]; 
     [offlineView setBackgroundColor:[UIColor colorWithWhite:0 alpha:0.7]]; 
     [offlineView setAlpha:0]; 

     offlineLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; 
     [offlineLabel setFont:[UIFont fontWithName:@"Verdana" size:30.0]]; 
     [offlineLabel setBackgroundColor:[UIColor clearColor]]; 
     [offlineLabel setTextAlignment:UITextAlignmentCenter]; 
     [offlineLabel setTextColor:[UIColor whiteColor]]; 
     [offlineLabel setCenter:[offlineView center]]; 
     [offlineLabel setText:@"OFFLINE"]; 

     [offlineView addSubview:offlineLabel]; 
     [[self window] addSubview:offlineView]; 

     [UIView animateWithDuration:0.3 animations:^{ 
      [offlineView setAlpha:1.0]; 
     }]; 

     [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES]; 
    } 
} 
+0

मैंने इस विधि का उपयोग किया लेकिन मैं आपको एक चीज़ के बारे में चेतावनी देता हूं। अधिसूचना केंद्र नोटिफ़ को "यादृच्छिक" क्रम में वितरित करेगा। इसलिए एक व्यू कंट्रोलर इसे और बाद में प्राप्त करेगा, जिससे आपके ऐप में असंगतता हो जाएगी। हो सकता है कि आप दो नोटफ के बीच भाग लेंगे: व्यू कंट्रोलर पर "ऑनलाइन" देखें, दूसरा "ऑफलाइन" देखें ... मेरा सुझाव है कि केवल एक वर्ग, शायद आपका ऐपडिलेगेट, रजिस्टर करें और फिर संपूर्ण ऐप को आंतरिक एपीआई के माध्यम से चेक करें कक्षा। अब आपके पास अपनी सभी कक्षाओं के लिए एक सतत दृश्य होगा। – malaba

+0

@मालबा - आप बिल्कुल सही हैं! मैं ऐपडिलेगेट से –

+2

तक पहुंच क्षमता का प्रबंधन कर रहा हूं, आप 'आरकेआरचैबिलिटीडिड चेंज नॉटिफिकेशन' के लिए पंजीकरण कर सकते हैं और रेस्टकिट सामान का उपयोग करने के लिए कक्षा 'आरकेआरचैबिलिटी ऑब्सर्वर' के साथ खेल सकते हैं। – malaba

0

कृपया रेस्टकिट का संस्करण देखें; RestKit के नए संस्करण में प्रबंधित ऑब्जेक्ट स्टोर से कैश किए गए डेटा को प्राप्त करने के थोड़ा बदलाव आया है। मेरे पास इस मशीन पर उदाहरण नहीं है; लेकिन अगर आपको और मदद की ज़रूरत है (क्योंकि यह एक पुराना सवाल है) कृपया उत्तर दें।

संबंधित मुद्दे