mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-01-12 22:51:50 +08:00
Introduces four modes for handling background requests: * RKRequestBackgroundPolicyNone - The default behavior replicating pre-background behavior. No special action is taken with regards to backgrounding. * RKRequestBackgroundPolicyCancel - On transition to the background, requests with this policy set will be cancelled automatically and the delegate informed. * RKRequestBackgroundPolicyContinue - Requests with this policy will be continued in the background after the app has been transitioned. * RKRequestBackgroundPolicyRequeue - Requests with this policy will be cancelled and then immediately placed onto the queue for processing the next time the app is returned to the foreground.
204 lines
5.5 KiB
Objective-C
204 lines
5.5 KiB
Objective-C
//
|
|
// RKRequestQueue.m
|
|
// RestKit
|
|
//
|
|
// Created by Blake Watters on 12/1/10.
|
|
// Copyright 2010 Two Toasters. All rights reserved.
|
|
//
|
|
|
|
#import <UIKit/UIKit.h>
|
|
#import "RKRequestQueue.h"
|
|
#import "RKResponse.h"
|
|
#import "RKNotifications.h"
|
|
#import "RKClient.h"
|
|
|
|
static RKRequestQueue* gSharedQueue = nil;
|
|
|
|
static const NSTimeInterval kFlushDelay = 0.3;
|
|
static const NSInteger kMaxConcurrentLoads = 5;
|
|
|
|
@implementation RKRequestQueue
|
|
|
|
@synthesize suspended = _suspended;
|
|
|
|
+ (RKRequestQueue*)sharedQueue {
|
|
if (!gSharedQueue) {
|
|
gSharedQueue = [[RKRequestQueue alloc] init];
|
|
}
|
|
return gSharedQueue;
|
|
}
|
|
|
|
+ (void)setSharedQueue:(RKRequestQueue*)requestQueue {
|
|
if (gSharedQueue != requestQueue) {
|
|
[gSharedQueue release];
|
|
gSharedQueue = [requestQueue retain];
|
|
}
|
|
}
|
|
|
|
- (id)init {
|
|
if ((self = [super init])) {
|
|
_requests = [[NSMutableArray alloc] init];
|
|
_suspended = NO;
|
|
_totalLoading = 0;
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(responseDidLoad:)
|
|
name:RKResponseReceivedNotification
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(responseDidLoad:)
|
|
name:RKRequestFailedWithErrorNotification
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(willTransitionToBackground)
|
|
name:UIApplicationDidEnterBackgroundNotification
|
|
object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(willTransitionToForeground)
|
|
name:UIApplicationWillEnterForegroundNotification
|
|
object:nil];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
[_queueTimer invalidate];
|
|
[_requests release];
|
|
_requests = nil;
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)loadNextInQueueDelayed {
|
|
if (!_queueTimer) {
|
|
_queueTimer = [NSTimer scheduledTimerWithTimeInterval:kFlushDelay
|
|
target:self
|
|
selector:@selector(loadNextInQueue)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
}
|
|
}
|
|
|
|
- (void)loadNextInQueue {
|
|
// This makes sure that the Request Queue does not fire off any requests until the Reachability state has been determined.
|
|
if ([[[RKClient sharedClient] baseURLReachabilityObserver] networkStatus] == RKReachabilityIndeterminate ||
|
|
self.suspended) {
|
|
_queueTimer = nil;
|
|
[self loadNextInQueueDelayed];
|
|
return;
|
|
}
|
|
|
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
_queueTimer = nil;
|
|
|
|
NSArray* requestsCopy = [NSArray arrayWithArray:_requests];
|
|
for (RKRequest* request in requestsCopy) {
|
|
if (![request isLoading] && ![request isLoaded] && _totalLoading < kMaxConcurrentLoads) {
|
|
++_totalLoading;
|
|
[request sendAsynchronously];
|
|
}
|
|
}
|
|
|
|
if (_requests.count && !_suspended) {
|
|
[self loadNextInQueueDelayed];
|
|
}
|
|
|
|
[pool drain];
|
|
}
|
|
|
|
- (void)setSuspended:(BOOL)isSuspended {
|
|
_suspended = isSuspended;
|
|
|
|
if (!_suspended) {
|
|
[self loadNextInQueue];
|
|
} else if (_queueTimer) {
|
|
[_queueTimer invalidate];
|
|
_queueTimer = nil;
|
|
}
|
|
}
|
|
|
|
- (void)sendRequest:(RKRequest*)request {
|
|
[_requests addObject:request];
|
|
[self loadNextInQueue];
|
|
}
|
|
|
|
- (void)cancelRequest:(RKRequest*)request loadNext:(BOOL)loadNext {
|
|
if ([_requests containsObject:request] && ![request isLoaded]) {
|
|
[request cancel];
|
|
|
|
[_requests removeObject:request];
|
|
_totalLoading--;
|
|
|
|
if (loadNext) {
|
|
[self loadNextInQueue];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)cancelRequest:(RKRequest*)request {
|
|
[self cancelRequest:request loadNext:YES];
|
|
}
|
|
|
|
- (void)cancelRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate {
|
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
NSArray* requestsCopy = [NSArray arrayWithArray:_requests];
|
|
for (RKRequest* request in requestsCopy) {
|
|
if (request.delegate && request.delegate == delegate) {
|
|
[self cancelRequest:request];
|
|
}
|
|
}
|
|
[pool drain];
|
|
}
|
|
|
|
- (void)cancelAllRequests {
|
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
|
NSArray* requestsCopy = [NSArray arrayWithArray:_requests];
|
|
for (RKRequest* request in requestsCopy) {
|
|
[self cancelRequest:request loadNext:NO];
|
|
}
|
|
[pool drain];
|
|
}
|
|
|
|
- (BOOL)containsRequest:(RKRequest*)request {
|
|
return [_requests containsObject:request];
|
|
}
|
|
|
|
/**
|
|
* Invoked via observation when a request has loaded a response. Remove
|
|
* the completed request from the queue and continue processing
|
|
*/
|
|
- (void)responseDidLoad:(NSNotification*)notification {
|
|
if (notification.object) {
|
|
// Our RKRequest completed and we're notified with an RKResponse object
|
|
if ([notification.object isKindOfClass:[RKResponse class]]) {
|
|
RKRequest* request = [(RKResponse*)notification.object request];
|
|
[_requests removeObject:request];
|
|
_totalLoading--;
|
|
|
|
// Our RKRequest failed and we're notified with the original RKRequest object
|
|
} else if ([notification.object isKindOfClass:[RKRequest class]]) {
|
|
RKRequest* request = (RKRequest*)notification.object;
|
|
[_requests removeObject:request];
|
|
_totalLoading--;
|
|
}
|
|
|
|
[self loadNextInQueue];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Background Request Support
|
|
|
|
- (void)willTransitionToBackground {
|
|
// Suspend the queue so background requests do not trigger additional requests on state changes
|
|
self.suspended = YES;
|
|
}
|
|
|
|
- (void)willTransitionToForeground {
|
|
self.suspended = NO;
|
|
}
|
|
|
|
@end
|