mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-19 13:09:19 +08:00
First cut at queue support.
This commit is contained in:
@@ -18,3 +18,4 @@
|
||||
*/
|
||||
extern NSString* const kRKRequestSentNotification;
|
||||
extern NSString* const kRKResponseReceivedNotification;
|
||||
extern NSString* const kRKRequestFailedWithErrorNotification;
|
||||
@@ -10,3 +10,4 @@
|
||||
|
||||
NSString* const kRKRequestSentNotification = @"kRKRequestSentNotification";
|
||||
NSString* const kRKResponseReceivedNotification = @"kRKRespongReceivedNotification";
|
||||
NSString* const kRKRequestFailedWithErrorNotification = @"kRKRequestFailedWithErrorNotification";
|
||||
|
||||
@@ -61,11 +61,13 @@ typedef enum RKRequestMethod {
|
||||
* If the object implements the RKRequestDelegate protocol,
|
||||
* it will receive request lifecycle event messages.
|
||||
*/
|
||||
// TODO: Should be RKRequestDelegate instead of id
|
||||
@property(nonatomic, assign) id delegate;
|
||||
|
||||
/**
|
||||
* The selector to invoke when the request is completed
|
||||
*/
|
||||
// TODO: Eliminate callback in favor of a delegate method (requestDidLoadResponse:) for simplicity
|
||||
@property(nonatomic, assign) SEL callback;
|
||||
|
||||
/**
|
||||
@@ -113,7 +115,8 @@ typedef enum RKRequestMethod {
|
||||
- (id)initWithURL:(NSURL*)URL delegate:(id)delegate callback:(SEL)callback;
|
||||
|
||||
/**
|
||||
* Send the request asynchronously
|
||||
* Send the request asynchronously. It will be added to the queue and
|
||||
* dispatched as soon as possible.
|
||||
*/
|
||||
- (void)send;
|
||||
|
||||
@@ -154,6 +157,7 @@ typedef enum RKRequestMethod {
|
||||
*
|
||||
* Modeled off of TTURLRequest
|
||||
*/
|
||||
// TODO: Add a didLoadResponse: delegate method in place off callback
|
||||
@protocol RKRequestDelegate
|
||||
@optional
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "RKRequest.h"
|
||||
#import "RKRequestQueue.h"
|
||||
#import "RKResponse.h"
|
||||
#import "NSDictionary+RKRequestSerialization.h"
|
||||
#import "RKNotifications.h"
|
||||
@@ -115,6 +116,10 @@
|
||||
}
|
||||
|
||||
- (void)send {
|
||||
[[RKRequestQueue sharedQueue] sendRequest:self];
|
||||
}
|
||||
|
||||
- (void)fireAsynchronousRequest {
|
||||
[self addHeadersToRequest];
|
||||
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"Sending %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
||||
|
||||
63
Code/Network/RKRequestQueue.h
Normal file
63
Code/Network/RKRequestQueue.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// RKRequestQueue.h
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 12/1/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RKRequest.h"
|
||||
|
||||
/**
|
||||
* A lightweight queue implementation responsible
|
||||
* for dispatching and managing RKRequest objects
|
||||
*/
|
||||
@interface RKRequestQueue : NSObject {
|
||||
NSMutableArray* _requests;
|
||||
NSInteger _totalLoading;
|
||||
NSTimer* _queueTimer;
|
||||
BOOL _suspended;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag that determines if new load requests are allowed to reach the network.
|
||||
*
|
||||
* Because network requests tend to slow down performance, this property can be used to
|
||||
* temporarily delay them. All requests made while suspended are queued, and when
|
||||
* suspended becomes false again they are executed.
|
||||
*/
|
||||
@property (nonatomic) BOOL suspended;
|
||||
|
||||
/**
|
||||
* Return the global queue
|
||||
*/
|
||||
+ (RKRequestQueue*)sharedQueue;
|
||||
|
||||
/**
|
||||
* Set the global queue
|
||||
*/
|
||||
+ (void)setSharedQueue:(RKRequestQueue*)requestQueue;
|
||||
|
||||
/**
|
||||
* Add an asynchronous request to the queue and send it as
|
||||
* as soon as possible
|
||||
*/
|
||||
- (void)sendRequest:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Cancel a request that is in progress
|
||||
*/
|
||||
- (void)cancelRequest:(RKRequest*)request;
|
||||
|
||||
/**
|
||||
* Cancel all requests with a given delegate
|
||||
*/
|
||||
- (void)cancelRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate;
|
||||
|
||||
/**
|
||||
* Cancel all active or pending requests.
|
||||
*/
|
||||
- (void)cancelAllRequests;
|
||||
|
||||
@end
|
||||
141
Code/Network/RKRequestQueue.m
Normal file
141
Code/Network/RKRequestQueue.m
Normal file
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// RKRequestQueue.m
|
||||
// RestKit
|
||||
//
|
||||
// Created by Blake Watters on 12/1/10.
|
||||
// Copyright 2010 Two Toasters. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RKRequestQueue.h"
|
||||
#import "RKResponse.h"
|
||||
#import "RKNotifications.h"
|
||||
|
||||
static RKRequestQueue* gSharedQueue = nil;
|
||||
|
||||
static const NSTimeInterval kFlushDelay = 0.3;
|
||||
static const NSTimeInterval kTimeout = 300.0;
|
||||
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:kRKResponseReceivedNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(responseDidLoad:)
|
||||
name:kRKRequestFailedWithErrorNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_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)dispatchRequest:(RKRequest*)request {
|
||||
[request performSelector:@selector(fireAsynchronousRequest)];
|
||||
}
|
||||
|
||||
- (void)loadNextInQueue {
|
||||
_queueTimer = nil;
|
||||
|
||||
for (int i = 0;
|
||||
i < kMaxConcurrentLoads && _totalLoading < kMaxConcurrentLoads
|
||||
&& _requests.count;
|
||||
++i) {
|
||||
RKRequest* request = [[_requests objectAtIndex:0] retain];
|
||||
[_requests removeObjectAtIndex:0];
|
||||
[self dispatchRequest:request];
|
||||
[request release];
|
||||
}
|
||||
|
||||
if (_requests.count && !_suspended) {
|
||||
[self loadNextInQueueDelayed];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSuspended:(BOOL)isSuspended {
|
||||
_suspended = isSuspended;
|
||||
|
||||
if (!_suspended) {
|
||||
[self loadNextInQueue];
|
||||
} else if (_queueTimer) {
|
||||
[_queueTimer invalidate];
|
||||
_queueTimer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendRequest:(RKRequest*)request {
|
||||
if (_suspended || _totalLoading == kMaxConcurrentLoads) {
|
||||
[_requests addObject:request];
|
||||
} else {
|
||||
++_totalLoading;
|
||||
[self dispatchRequest:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelRequest:(RKRequest*)request {
|
||||
[request cancel];
|
||||
}
|
||||
|
||||
- (void)cancelRequestsWithDelegate:(NSObject<RKRequestDelegate>*)delegate {
|
||||
for (RKRequest* request in _requests) {
|
||||
if (request.delegate && request.delegate == delegate) {
|
||||
[request cancel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelAllRequests {
|
||||
for (RKRequest* request in [[[_requests copy] autorelease] objectEnumerator]) {
|
||||
[request cancel];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked via observation when a request has loaded a response. Remove
|
||||
* the completed request from the queue and continue processing
|
||||
*/
|
||||
- (void)responseDidLoad:(NSNotification*)notification {
|
||||
_totalLoading--;
|
||||
[self loadNextInQueue];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
|
||||
// Handle basic auth
|
||||
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
if ([challenge previousFailureCount] == 0) {
|
||||
NSURLCredential *newCredential;
|
||||
newCredential=[NSURLCredential credentialWithUser:[NSString stringWithFormat:@"%@", _request.username]
|
||||
@@ -81,16 +81,16 @@
|
||||
_httpURLResponse = [response retain];
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
NSDate* receivedAt = [NSDate date]; // TODO - Carry around this timestamp on the response or request?
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[_request HTTPMethod], @"HTTPMethod", [_request URL], @"URL", receivedAt, @"receivedAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:self userInfo:userInfo];
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
[[_request delegate] performSelector:[_request callback] withObject:self];
|
||||
|
||||
if ([[_request delegate] respondsToSelector:@selector(requestDidFinishLoad:)]) {
|
||||
[[_request delegate] requestDidFinishLoad:_request];
|
||||
}
|
||||
|
||||
NSDate* receivedAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[_request HTTPMethod], @"HTTPMethod", [_request URL], @"URL", receivedAt, @"receivedAt", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:self userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||
@@ -100,6 +100,11 @@
|
||||
if ([[_request delegate] respondsToSelector:@selector(request:didFailLoadWithError:)]) {
|
||||
[[_request delegate] request:_request didFailLoadWithError:error];
|
||||
}
|
||||
|
||||
NSDate* receivedAt = [NSDate date];
|
||||
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[_request HTTPMethod], @"HTTPMethod",
|
||||
[_request URL], @"URL", receivedAt, @"receivedAt", error, @"error", nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestFailedWithErrorNotification object:_request userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
@@ -108,7 +113,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)localizedStatusCodeString {
|
||||
return [NSHTTPURLResponse localizedStringForStatusCode:[self statusCode]];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user