简体   繁体   English

如果需要委托函数,如何直接返回由NSURLConnection加载的数据?

[英]How to return data directly which was loaded by NSURLConnection if delegate functions are needed?

A short explanation what I want to do: I'm using NSURLConnection to connect to a SSL webpage which is my API. 简短说明:我要使用NSURLConnection连接到我的API网页SSL。 The servers certificate is a self signed one so you have to accept it, for example in a web browser. 服务器证书是一种自签名证书,因此您必须接受它,例如在Web浏览器中。 I've found a solution on Stack Overflow how to do the trick ( How to use NSURLConnection to connect with SSL for an untrusted cert? ) 我在Stack Overflow上找到了一种解决方案,该技巧如何解决( 如何使用NSURLConnection与SSL连接以获取不受信任的证书?

So I've added the NSURLConnection delegate to use methods like "didReceiveAuthenticationChallenge". 因此,我添加了NSURLConnection委托以使用诸如“ didReceiveAuthenticationChallenge”之类的方法。 As a result of that I cannot use this: 因此,我不能使用此:

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

because there is no possibility to use the delegate functions in this case. 因为在这种情况下不可能使用委托函数。 My question is the following: I need a function which looks like this: 我的问题如下:我需要一个看起来像这样的函数:

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

how can I return a NSDictionary by using this? 如何使用此方法返回NSDictionary? As far as you know the delegate function of NSURLConnection are called now and the response isn't available at this point. 据您所知,现在已调用NSURLConnection的委托函数,并且此刻尚无响应。 The problem is that the view controller depends on this response so I need to return the dictionary directly... Does anybody know a solution for this? 问题在于视图控制器依赖于此响应,因此我需要直接返回字典...有人知道解决方案吗? What about a callback function? 回调函数呢?

okay, I've found a solution for that. 好的,我已经找到了解决方案。 A very good thing is to use blocks in objective-c. 一个很好的事情是在Objective-C中使用块。

First of all you have to add some methods to NSURLRequest and NSURL: 首先,您必须向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

And than just implement the follwing class: 而不仅仅是实现下面的类:

@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);

}

Now you can do the follwing, some kind of callback function: 现在,您可以执行以下某种回调函数:

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
    }

}];

Here you can find the orginal german solution by ICNH: Asynchrones I/O mit Bloecken 在这里,您可以找到ICNH的原始德语解决方案: Asynchrones I / O mit Bloecken

Thank you very much for this! 非常感谢您!

My suggestion would be to use some other delegate methods for NSURLConnection like connection:didReceiveResponse: or connection:didReceiveData: . 我的建议是为NSURLConnection使用其他一些委托方法,例如connection:didReceiveResponse:connection:didReceiveData: You should probably keep a use a set up like so: 您可能应该像这样使用设置:

@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];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM