2010-01-29 20 views
0

J'ai besoin d'utiliser un NSTimer pour annuler mon NSURLRequest avant 75 secondes (le temps que j'ai mesuré quel que soit le timeout que j'ai défini). J'utilise les classes XMLRPC d'Eric Czarny. Le XMLRPCConnection est essentiellement une image de la classe NSURLConnection.iphone NSURLConnection NSTimer fonctionne dans initWithRequest mais provoque une erreur de sélecteur non reconnue dans sendSynchronousRequest

est ici l'interface et le fichier de mise en œuvre:

#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 

fichier de mise en œuvre:

#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 

La minuterie est réglée dans la méthode initWithXMLRPCRequest fonctionne très bien, mais si elle est définie dans la méthode sendSycnhronousXMLRPCRequest, je reçois l'erreur suivante:

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 
) 

Je ne sais pas comprendre, j'ai déclaré la méthode timeOut dans le fichier d'implémentation?

Répondre

0

Je pense que votre méthode timedOut devrait être un public. Non caché dans une catégorie avec des méthodes privées.

+0

Cela est également vrai - je viens de le répara. Les interfaces sont mélangées avec l'implémentation et je me suis complètement perdu dans ça. – Leonard

0

La méthode que les appels de minuterie doit être de la forme:

- (void)timerFireMethod:(NSTimer*)theTimer; 

Le nom est arbitraire, mais vous devez retourner vide et doit accepter une minuterie. Je soupçonne que c'est la source de votre erreur. Dans tous les cas, vous devez le remplacer par le formulaire standard.

+0

Sur l'iPhone NSTimers fonctionnent très bien sans l'argument NSTimer. Je les utilise tout le temps comme ça. L'erreur est ailleurs. Le message d'erreur pointe vers la bibliothèque XML-RPC. Il mentionne 'timedOut'. –

+0

Merci! Il semble être le fait que la méthode synchronisée est une méthode de classe: https://devforums.apple.com/thread/37609?tstart=0 – Leonard