Hi,
I need to use an NSTimer to cancel my NSURLRequest before 75 seconds (the time I measured regardless of the timeout I set). I'm using the XMLRPC classes by Eric Czarny. The XMLRPCConnection is basically an image of the NSURLConnection class.
Here's the interface and the implementation file:
#import <Foundation/Foundation.h>
@class XMLRPCRequest, XMLRPCResponse;
/* XML-RPC Connecion Notifications */
extern NSString *XMLRPCRequestFailedNotification;
extern NSString *XMLRPCSentRequestNotification;
extern NSString *XMLRPCReceivedResponseNotification;
@interface XMLRPCConnection : NSObject {
NSURLConnection *_connection;
NSString *_method;
NSMutableData *_data;
id _delegate;
UIViewController* _requester;
}
@property(nonatomic, retain) NSMutableData* _data;
- (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate;
- (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate requester:(UIViewController*)requester;
- (void) timedOut;
#pragma mark -
+ (XMLRPCResponse *)sendSynchronousXMLRPCRequest: (XMLRPCRequest *)request;
#pragma mark -
- (void)cancel;
@end
#pragma mark -
@interface NSObject (XMLRPCConnectionDelegate)
- (void)connection: (XMLRPCConnection *)connection didReceiveResponse: (XMLRPCResponse *)response
forMethod: (NSString *)method;
- (void)connection: (XMLRPCConnection *)connection didFailWithError: (NSError *)error
forMethod: (NSString *)method;
@end
Implementation file:
#import "XMLRPCConnection.h"
#import "XMLRPCRequest.h"
#import "XMLRPCResponse.h"
NSString *XMLRPCRequestFailedNotification = @"XML-RPC Failed Receiving Response";
NSString *XMLRPCSentRequestNotification = @"XML-RPC Sent Request";
NSString *XMLRPCReceivedResponseNotification = @"XML-RPC Successfully Received Response";
@interface XMLRPCConnection (XMLRPCConnectionPrivate)
- (void)connection: (NSURLConnection *)connection didReceiveData: (NSData *)data;
- (void)connection: (NSURLConnection *)connection didFailWithError: (NSError *)error;
- (void)connectionDidFinishLoading: (NSURLConnection *)connection;
- (void) timedOut;
@end
#pragma mark -
@implementation XMLRPCConnection
@synthesize _data;
- (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate requester:(UIViewController*)requester {
if (self = [super init])
{
_connection = [[NSURLConnection alloc] initWithRequest: [request request] delegate: self];
_delegate = delegate;
_requester = requester;
// set the timer for timed out requests here
NSTimer* connectionTimer = [NSTimer timerWithTimeInterval:10.0f target:self selector:@selector(timedOut) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:connectionTimer forMode:NSDefaultRunLoopMode];
if (_connection != nil)
{
_method = [[NSString alloc] initWithString: [request method]];
_data = [[NSMutableData alloc] init];
[[NSNotificationCenter defaultCenter] postNotificationName:
XMLRPCSentRequestNotification object: nil];
}
else
{
if ([_delegate respondsToSelector: @selector(connection:didFailWithError:forMethod:)])
{
[_delegate connection: self didFailWithError: nil forMethod: [request method]];
}
return nil;
}
}
return self;
}
- (void) timedOut {
NSLog(@"connection timed out now!");
}
#pragma mark -
+ (XMLRPCResponse *)sendSynchronousXMLRPCRequest: (XMLRPCRequest *)request
{
NSURLResponse *urlres;
//NSHTTPURLResponse *urlres;
NSError *err = NULL;
// set the timer for timed out requests here
NSTimer* connectionTimer = [NSTimer timerWithTimeInterval:10.0f target:self selector:@selector(timedOut) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:connectionTimer forMode:NSDefaultRunLoopMode];
NSData *data = [NSURLConnection sendSynchronousRequest: [request request]
returningResponse: &urlres error: &err];
if ([urlres isKindOfClass:[NSHTTPURLResponse class]]) {
NSLog(@"Received status code: %d %@", [(NSHTTPURLResponse *) urlres statusCode],
[NSHTTPURLResponse localizedStringForStatusCode:[(NSHTTPURLResponse *) urlres statusCode]]) ;
NSDictionary* headerFields = [(NSHTTPURLResponse*)urlres allHeaderFields];
NSArray* cookie = [NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:[request host]];
if ([cookie count] != 0) {
NSString* cookieName = [[cookie objectAtIndex:0] name];
NSString* cookieValue = [[cookie objectAtIndex:0] value];
NSLog(@"cookie name=value: %@=%@", cookieName, cookieValue );
[[User getInstance] setCookieID:[NSString stringWithFormat:@"%@=%@", cookieName, cookieValue] ];
} else {
NSLog(@"cookie array empty!");
}
}
// if an error occured while processing the request, this variable will be set
if( err != NULL )
{
//TODO: we may need to create a XMLRPCResponse with the error. and return
return (id) err;
}
if (data != nil)
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"response is: %@",str);
if ( ! str ) {
str = [[NSString alloc] initWithData:data encoding:[NSString defaultCStringEncoding]];
data = [str dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
}
//Check for HTML code 400 or greater in response statusCode (from header) and throw error if so
if ([urlres isKindOfClass:[NSHTTPURLResponse class]]) {
// HTTP codes equal or higher than 400 signifies an error
if ([(NSHTTPURLResponse *) urlres statusCode] >= 400) {
// NSLog(@"Received status code: %d %@", [(NSHTTPURLResponse *) urlres statusCode],
// [NSHTTPURLResponse localizedStringForStatusCode:[(NSHTTPURLResponse *) urlres statusCode]]) ;
NSString *errorIntString = [NSString stringWithFormat:@"%d", [(NSHTTPURLResponse *) urlres statusCode]];
NSString *stringForStatusCode = [NSHTTPURLResponse localizedStringForStatusCode:[(NSHTTPURLResponse *) urlres statusCode]];
NSString *errorString = [[errorIntString stringByAppendingString:@" "] stringByAppendingString:stringForStatusCode];
NSInteger code = -1; //This is not significant, just a number with no meaning
NSDictionary *usrInfo = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
err = [NSError errorWithDomain:@"org.wordpress.iphone" code:code userInfo:usrInfo];
return (id) err;
}
}
//[str release];
return [[[XMLRPCResponse alloc] initWithData: data] autorelease];
}
return nil;
}
#pragma mark -
- (void)cancel
{
[_connection cancel];
[_connection autorelease];
}
#pragma mark -
- (void)dealloc
{
[_method autorelease];
[_data autorelease];
[super dealloc];
}
@end
#pragma mark -
@implementation XMLRPCConnection (XMLRPCConnectionPrivate)
....
@end
The timer set in the initWithXMLRPCRequest method works fine, but if it's set in the sendSycnhronousXMLRPCRequest method, I get the following error:
2010-01-29 11:36:40.442 ActiveE[1071:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[XMLRPCConnection timedOut]: unrecognized selector sent to class 0x32610'
2010-01-29 11:36:40.443 ActiveE[1071:207] Stack: (
31044699,
2497855305,
31426811,
30996086,
30848706,
609709,
30829248,
30825544,
39135117,
39135314,
3100675
)
I don't understand, I did declare the timeOut method in the implementation file?