Как вернуть данные напрямую, которые были загружены NSURLConnection, если необходимы функции делегата? - PullRequest
2 голосов
/ 26 ноября 2011

Краткое объяснение того, что я хочу сделать: я использую NSURLConnection для подключения к веб-странице SSL, которая является моим API.Сертификат сервера является самозаверяющим, поэтому вы должны принять его, например, в веб-браузере.Я нашел решение по переполнению стека, как это сделать ( Как использовать NSURLConnection для соединения с SSL для ненадежного сертификата? )

Поэтому я добавил делегат NSURLConnection виспользуйте такие методы, как «didReceiveAuthenticationChallenge».В результате я не могу использовать это:

NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];

, потому что в этом случае нет возможности использовать функции делегата.Мой вопрос заключается в следующем: мне нужна функция, которая выглядит следующим образом:

- (NSDictionary *)getData :  (NSArray *)parameter {
    [...|
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
    [...]
    return myDictionary; 
}

как я могу вернуть NSDictionary с помощью этого?Насколько вам известно, функция делегата NSURLConnection вызывается сейчас, и ответ на данный момент недоступен.Проблема в том, что контроллер представления зависит от этого ответа, поэтому мне нужно вернуть словарь напрямую ... Кто-нибудь знает решение для этого?Как насчет функции обратного вызова?

Ответы [ 2 ]

1 голос
/ 01 декабря 2011

хорошо, я нашел решение для этого. Очень хорошая вещь - использовать блоки в target-c.

Прежде всего вы должны добавить несколько методов в NSURLRequest и NSURL:

@implementation NSURLRequest (URLFetcher)

- (void)fetchDataWithResponseBlock:(void (^)(FetchResponse *response))block {
    FetchResponse *response = [[FetchResponse alloc] initWithBlock:block];
    [[NSURLConnection connectionWithRequest:self delegate:response] start];
    [response release];
}

@end

@implementation NSURL (URLFetcher)

- (void)fetchDataWithResponseBlock:(void (^)(FetchResponse *response))block {
    [[NSURLRequest requestWithURL:self] fetchDataWithResponseBlock:block];
}

@end

А чем просто реализовать следующий класс:

@implementation FetchResponse

- (id)initWithBlock:(void(^)(FetchResponse *response))block {
    if ((self = [super init])) {
        _block = [block copy];
    }
    return self;
}

- (NSData *)data {
    return _data;
}

- (NSURLResponse *)response {
    return _response;
}

- (NSError *)error {
    return _error;
}

- (NSInteger)statusCode {

    if ([_response isKindOfClass:[NSHTTPURLResponse class]]) return [(NSHTTPURLResponse *)_response statusCode];

    return 0;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    _response = response; 

}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    if (!_data) _data = [[NSMutableData alloc] init];

    [_data appendData:data];

}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    _block(self);

}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {

    _error = error;
    _block(self);

}

Теперь вы можете выполнить следующую функцию обратного вызова:

NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://..."];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"accept"];

[request fetchDataWithResponseBlock:^(FetchResponse *response) {

    if (response.error || response.statusCode != 200) 
        NSLog(@"Error: %@", response.error); 

    else {

        //use response.data
    }

}];

Здесь вы можете найти оригинальное немецкое решение ICNH: Асинхронный ввод / вывод с Bloecken

Большое спасибо за это!

0 голосов
/ 28 ноября 2011

Я бы предложил использовать некоторые другие методы делегата для NSURLConnection, такие как connection:didReceiveResponse: или connection:didReceiveData:. Вы, вероятно, должны использовать настройку так:

@interface MyClass : NSObject {
…
    NSMutableData *responseData;   
}
…
@end

- (void)startConnection {
    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
    if (theConnection) {
        responseData = [[NSMutableData data] retain];
    } else {
        // connection failed
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    // connection could have been redirected, reset the data
    [responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // connection is done, do what you want
    ………
    // don't leak the connection or the response when you are done with them
    [connection release];
    [responseData release];
}
// for your authentication challenge
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace (NSURLProtectionSpace *)protectionSpace {
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    if ([trustedHosts containsObject:challenge.protectionSpace.host])
      [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
...