Last active
July 16, 2020 10:51
-
-
Save SQiShER/5009086 to your computer and use it in GitHub Desktop.
Here is my solution for a better synchronous NSURLConnection. Although asynchronous NSURLConnections are usually a good way to go, sometimes there is just no way around waiting (and blocking) until a request finished. NSURLConnection offers a method to perform synchronous requests, but it is far from perfect and has some serious flaws. In my cas…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@interface URLConnection : NSObject <NSURLConnectionDataDelegate, NSURLConnectionDelegate> | |
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request | |
returningResponse:(NSURLResponse **)response | |
error:(NSError **)error; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "URLConnection.h" | |
@interface URLConnection () | |
@property(nonatomic, strong) NSURLConnection *connection; | |
@property(nonatomic, strong) NSURLResponse *response; | |
@property(nonatomic, strong) NSData *responseData; | |
@property(nonatomic, strong) NSCondition *condition; | |
@property(nonatomic, strong) NSError *error; | |
@property(nonatomic) BOOL connectionDidFinishLoading; | |
@end | |
@implementation URLConnection | |
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request | |
returningResponse:(NSURLResponse **)response | |
error:(NSError **)error { | |
return [[[URLConnection alloc] init] sendSynchronousRequest:request returningResponse:response error:error]; | |
} | |
- (id)init { | |
self = [super init]; | |
if (self) { | |
self.condition = [[NSCondition alloc] init]; | |
self.connection = nil; | |
self.connectionDidFinishLoading = NO; | |
self.error = nil; | |
self.response = nil; | |
self.responseData = [NSData data]; | |
} | |
return self; | |
} | |
- (NSData *)sendSynchronousRequest:(NSURLRequest *)request | |
returningResponse:(NSURLResponse **)response | |
error:(NSError **)error { | |
NSParameterAssert(request); | |
NSAssert(!self.connection, @"This method may only be called once"); | |
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; | |
[self.connection setDelegateQueue:[[NSOperationQueue alloc] init]]; | |
[self.connection start]; | |
[self waitForConnectionToFinishLoading]; | |
if (self.error != nil) { | |
if (response) *response = nil; | |
if (error) *error = self.error; | |
return nil; | |
} else { | |
if (response) *response = self.response; | |
if (error) *error = nil; | |
return self.responseData; | |
} | |
} | |
- (void)waitForConnectionToFinishLoading { | |
[self.condition lock]; | |
while (!self.connectionDidFinishLoading) { | |
[self.condition wait]; | |
} | |
[self.condition unlock]; | |
} | |
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { | |
self.response = response; | |
} | |
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { | |
NSMutableData *mutableResponse = self.responseData.mutableCopy; | |
[mutableResponse appendData:data]; | |
self.responseData = mutableResponse.copy; | |
} | |
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { | |
[self.condition lock]; | |
self.error = error; | |
self.connectionDidFinishLoading = YES; | |
[self.condition signal]; | |
[self.condition unlock]; | |
} | |
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { | |
[self.condition lock]; | |
self.connectionDidFinishLoading = YES; | |
[self.condition signal]; | |
[self.condition unlock]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello. I add didReceiveAuthenticationChallenge but not enter. why?:
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic] || [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM]) {
if ([challenge previousFailureCount] == 0) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:@"[email protected]"
password:@"Abril2020.sap"
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
else
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
NSLog (@"failed authentication");
// ...error will be handled by connection didFailWithError
self.error = [NSError errorWithDomain:@"" code:500 userInfo:@{@"Error reason": @"failed authentication"}];
}
}
}
Is NSURLAuthenticationMethodNTLM type
Thx