2010-01-29 2 views
0

Мне нужно использовать NSTimer для отмены моего NSURLRequest до 75 секунд (время, которое я измерял, независимо от установленного таймаута). Я использую классы XMLRPC Эрика Чарни. XMLRPCConnection - это в основном образ класса NSURLConnection.iphone NSURLConnection NSTimer работает в initWithRequest, но вызывает непризнанную ошибку выбора в sendSynchronousRequest

Вот интерфейс и файл реализации: файл

#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 

Реализация:

#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 

Таймер установлен в методе initWithXMLRPCRequest работает отлично, но если он установлен в методе sendSycnhronousXMLRPCRequest, я получаю следующая ошибка:

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 
) 

Я не понимаете, я объявлял метод timeOut в файле реализации?

ответ

0

Я думаю, что ваш метод timedOut должен быть общедоступным. Не скрыта в категории с частными методами.

+0

Это также верно - я только что отремонтировал его. Интерфейсы смешиваются с реализацией, и я полностью потерялся в этом. – Leonard

0

Метод, который вызовы таймера должен иметь вид:

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

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

+0

На iPhone NSTimers отлично работают без аргумента NSTimer. Я использую их все время. Ошибка в другом месте. Сообщение об ошибке указывает на библиотеку XML-RPC. В нем упоминается «timedOut». –

+0

Спасибо! Кажется, что синхронизированный метод является методом класса: https://devforums.apple.com/thread/37609?tstart=0 – Leonard

Смежные вопросы