2012-03-01 3 views
17

Я хочу использовать RestKit для приложения, которое должно работать как во время работы, так и в автономном режиме.Онлайн и автономная поддержка приложений RestKit iOS

Возможно, я не понимаю, как работает RestKit, но я думал, что это было (справедливо) легко реализовать.

В тестовой царапанию IOS приложение, которое я установить вещи следующим образом:

// 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"]; 

Объект пользователя осуществляется в соответствии с требованиями для поддержки CoreData:

@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 

Я тогда сделать вызов на сервер, чтобы получить пользователь с идентификатором 123, на пути "/ API/пользователей/123":

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

Это прекрасно работает. Но, когда я отключу Wi-Fi на своем Mac, приведенный выше код не извлекает пользователя из базы данных sqlite.

я получаю следующее сообщение об ошибке, а не в objectLoader:didFailWithError делегата:

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», я бы ожидал пользователь должен быть извлечен из локального кеша.

Кэш содержит запись пользователя с идентификатором 123 - в таблице ZUSER с 123 в столбце ZIDENTIFIER.

Есть ли какой-то шаг, который мне не хватает, чтобы заставить это работать? Может быть, еще один метод делегирования, который необходимо обработать , или вызывается, когда кэш попадает после таймаута ? Или я пытаюсь сделать что-то, что не обязательно что-то, что вы получите «из коробки» с помощью RestKit?

Cheers.

+0

Привет , Я пытаюсь сделать то же самое с RestKit 0.20.1 - любое обновление по этому вопросу? Вы получили эту работу? Ответ, который вы проверили, кажется, не отвечает на ваш вопрос ... Спасибо! – Diego

+1

Я проверил ответ ниже как правильный, потому что я взял предложение Джулиана использовать класс достижимости, чтобы проверить, был ли я онлайн или офлайн. Позже я закончил использование RestKit для онлайновых сообщений, а CoreData - для автономного хранения. – dbarros

+0

ОК спасибо! Я думаю, что я попытаюсь централизовать это в appdelegate - хотя для этого мне кажется, что лучше создать ядро ​​HTTP-операции, которое я тогда анализирую каждый раз, когда требуется синхронизация (возможно, периодически). – Diego

ответ

6

Вы можете использовать класс возвращаемости, чтобы определить, находится ли ваш клиент в автономном режиме или нет. Я использую этот класс очень часто в каждом проекте, который требует подключения к Интернету.

Вы просто запускаете уведомитель на конкретный хост. Во всем вашем контролере просмотра теперь вам просто нужно зарегистрировать методы в NSNotificationCenter, чтобы установить, например, BOOL isOnline, например, .

Выполняя эту практику, вы можете делать красивые вещи в своем приложении, например, накладывать приложение с плавным сообщением «Оффлайн».

https://gist.github.com/1182373

EDIT

Heres один пример с экрана входа в систему одного из моих проектов (извините за это количество кода, но это моя полная реализация):

- (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

Я использовал этот метод, но предупреждаю вас об одном. Центр уведомлений выдаст уведомление в «случайном порядке». Следовательно, один ViewController получит его, а другой позже, что приведет к несогласованности вашего приложения. Возможно, вы столкнетесь между двумя notif: on ViewController см. «Онлайн», другой - «офлайн» ... Я предлагаю зарегистрировать только один класс, возможно, ваш AppDelegate, а затем всю проверку приложения через внутренний API для этого класс. Теперь у вас будет постоянный взгляд на весь ваш класс. – malaba

+0

@malaba - Ты совершенно прав! Я управляю достижением из AppDelegate слишком –

+2

, вы можете зарегистрироваться для 'RKReachabilityDidChangeNotification' и играть с классом' RKReachabilityObserver', чтобы использовать материал RestKit. – malaba

0

Пожалуйста, проверьте версию RestKit; в новой версии RestKit существует несколько измененный подход к получению кэшированных данных из хранилища управляемых объектов. У меня нет примера на этой машине; но если вам нужна помощь больше (так как это довольно старый вопрос), ответьте.