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

发布于 2024-12-17 20:06:13 字数 921 浏览 2 评论 0原文

简短说明我想要做什么:我正在使用 NSURLConnection 连接到 SSL 网页,这是我的 API。服务器证书是自签名证书,因此您必须接受它,例如在 Web 浏览器中。我在 Stack Overflow 上找到了一个解决方案,如何解决这个问题(如何使用 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 的委托函数,并且此时响应不可用。问题是视图控制器依赖于这个响应,所以我需要直接返回字典...有人知道这个问题的解决方案吗?回调函数怎么样?

A short explanation what I want to do: I'm using NSURLConnection to connect to a SSL webpage which is my API. The servers certificate is a self signed one so you have to accept it, for example in a web browser. 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?)

So I've added the NSURLConnection delegate to use methods like "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? As far as you know the delegate function of NSURLConnection are called now and the response isn't available at this point. 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

几度春秋 2024-12-24 20:06:13

好的,我已经找到了解决方案。在 Objective-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 的原始德语解决方案: 异步 I/O mit Bloecken

非常感谢您!

okay, I've found a solution for that. A very good thing is to use blocks in objective-c.

First of all you have to add some methods to NSURLRequest and 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

Thank you very much for this!

我不会写诗 2024-12-24 20:06:13

我的建议是对 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];
}

My suggestion would be to use some other delegate methods for NSURLConnection like connection:didReceiveResponse: or 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];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文