iphone NSURLConnection NSTimer работает в initWithRequest, но вызывает нераспознанную ошибку селектора в sendSynchronousRequest - PullRequest
0 голосов
/ 29 января 2010

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

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

#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 в файле реализации?

Ответы [ 2 ]

0 голосов
/ 30 января 2010

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

0 голосов
/ 29 января 2010

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

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

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

...