Use magic to narrow the NSURLConnection performance gap to almost nothing :)
Showing
2 changed files
with
78 additions
and
39 deletions
| @@ -21,7 +21,7 @@ | @@ -21,7 +21,7 @@ | ||
| 21 | #import "ASIInputStream.h" | 21 | #import "ASIInputStream.h" |
| 22 | 22 | ||
| 23 | // Automatically set on build | 23 | // Automatically set on build |
| 24 | -NSString *ASIHTTPRequestVersion = @"v1.2-53 2009-12-19"; | 24 | +NSString *ASIHTTPRequestVersion = @"v1.2-54 2009-12-19"; |
| 25 | 25 | ||
| 26 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; | 26 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; |
| 27 | 27 | ||
| @@ -56,6 +56,10 @@ static NSError *ASITooMuchRedirectionError; | @@ -56,6 +56,10 @@ static NSError *ASITooMuchRedirectionError; | ||
| 56 | static NSMutableArray *bandwidthUsageTracker = nil; | 56 | static NSMutableArray *bandwidthUsageTracker = nil; |
| 57 | static unsigned long averageBandwidthUsedPerSecond = 0; | 57 | static unsigned long averageBandwidthUsedPerSecond = 0; |
| 58 | 58 | ||
| 59 | +// These are used for queuing persistent connections on the same connection | ||
| 60 | +static unsigned char streamNumber = 0; | ||
| 61 | +static void *streamIDs[4]; | ||
| 62 | + | ||
| 59 | // Records how much bandwidth all requests combined have used in the last second | 63 | // Records how much bandwidth all requests combined have used in the last second |
| 60 | static unsigned long bandwidthUsedInLastSecond = 0; | 64 | static unsigned long bandwidthUsedInLastSecond = 0; |
| 61 | 65 | ||
| @@ -116,6 +120,8 @@ static BOOL isiPhoneOS2; | @@ -116,6 +120,8 @@ static BOOL isiPhoneOS2; | ||
| 116 | // Start the read stream. Called by loadRequest, and again to restart the request when authentication is needed | 120 | // Start the read stream. Called by loadRequest, and again to restart the request when authentication is needed |
| 117 | - (void)startRequest; | 121 | - (void)startRequest; |
| 118 | 122 | ||
| 123 | +- (void)markAsFinished; | ||
| 124 | + | ||
| 119 | #if TARGET_OS_IPHONE | 125 | #if TARGET_OS_IPHONE |
| 120 | + (void)registerForNetworkReachabilityNotifications; | 126 | + (void)registerForNetworkReachabilityNotifications; |
| 121 | + (void)unsubscribeFromNetworkReachabilityNotifications; | 127 | + (void)unsubscribeFromNetworkReachabilityNotifications; |
| @@ -177,6 +183,11 @@ static BOOL isiPhoneOS2; | @@ -177,6 +183,11 @@ static BOOL isiPhoneOS2; | ||
| 177 | ASIUnableToCreateRequestError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnableToCreateRequestErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to create request (bad url?)",NSLocalizedDescriptionKey,nil]] retain]; | 183 | ASIUnableToCreateRequestError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnableToCreateRequestErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Unable to create request (bad url?)",NSLocalizedDescriptionKey,nil]] retain]; |
| 178 | ASITooMuchRedirectionError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASITooMuchRedirectionErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request failed because it redirected too many times",NSLocalizedDescriptionKey,nil]] retain]; | 184 | ASITooMuchRedirectionError = [[NSError errorWithDomain:NetworkRequestErrorDomain code:ASITooMuchRedirectionErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request failed because it redirected too many times",NSLocalizedDescriptionKey,nil]] retain]; |
| 179 | 185 | ||
| 186 | + // IDs that will be used for the four streams we'll create (see | ||
| 187 | + char i; | ||
| 188 | + for (i=0; i<4; i++) { | ||
| 189 | + streamIDs[i] = (void *)CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &i); | ||
| 190 | + } | ||
| 180 | #if TARGET_OS_IPHONE | 191 | #if TARGET_OS_IPHONE |
| 181 | isiPhoneOS2 = ((floorf([[[UIDevice currentDevice] systemVersion] floatValue]) == 2.0) ? YES : NO); | 192 | isiPhoneOS2 = ((floorf([[[UIDevice currentDevice] systemVersion] floatValue]) == 2.0) ? YES : NO); |
| 182 | #else | 193 | #else |
| @@ -502,7 +513,11 @@ static BOOL isiPhoneOS2; | @@ -502,7 +513,11 @@ static BOOL isiPhoneOS2; | ||
| 502 | 513 | ||
| 503 | // On Leopard, we'll create the thread ourselves | 514 | // On Leopard, we'll create the thread ourselves |
| 504 | } else { | 515 | } else { |
| 516 | + if ([self shouldRunInBackgroundThread]) { | ||
| 505 | [self performSelectorInBackground:@selector(startAsynchronous) withObject:nil]; | 517 | [self performSelectorInBackground:@selector(startAsynchronous) withObject:nil]; |
| 518 | + } else { | ||
| 519 | + [self startAsynchronous]; | ||
| 520 | + } | ||
| 506 | } | 521 | } |
| 507 | #endif | 522 | #endif |
| 508 | } | 523 | } |
| @@ -811,8 +826,23 @@ static BOOL isiPhoneOS2; | @@ -811,8 +826,23 @@ static BOOL isiPhoneOS2; | ||
| 811 | } | 826 | } |
| 812 | 827 | ||
| 813 | // Use a persistent connection if possible | 828 | // Use a persistent connection if possible |
| 829 | + if (shouldAttemptPersistentConnection) { | ||
| 814 | CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); | 830 | CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); |
| 815 | 831 | ||
| 832 | + // Based on http://lists.apple.com/archives/macnetworkprog/2008/Dec/msg00001.html | ||
| 833 | + // Basically, we aim to open a maximum of 4 connections (each one with a different id), and then subsequent requests will try to re-use the same stream, assuming we're connecting to the same server | ||
| 834 | + // I'm guessing this will perform less well when you're connecting to several different servers at once | ||
| 835 | + // But if you aren't, this appears to be the magic bullet for matching NSURLConnection's performance | ||
| 836 | + | ||
| 837 | + // We will re-use the previous ID for a synchronous request, since that probably gives us a greater chance of maximimising connection re-use | ||
| 838 | + if (![self isSynchronous]) { | ||
| 839 | + streamNumber++; | ||
| 840 | + if (streamNumber == 4) { | ||
| 841 | + streamNumber = 0; | ||
| 842 | + } | ||
| 843 | + } | ||
| 844 | + CFReadStreamSetProperty(readStream, CFSTR("ASIStreamID"), streamIDs[streamNumber]); | ||
| 845 | + } | ||
| 816 | 846 | ||
| 817 | // Handle proxy settings | 847 | // Handle proxy settings |
| 818 | 848 | ||
| @@ -889,6 +919,7 @@ static BOOL isiPhoneOS2; | @@ -889,6 +919,7 @@ static BOOL isiPhoneOS2; | ||
| 889 | return; | 919 | return; |
| 890 | } | 920 | } |
| 891 | 921 | ||
| 922 | + | ||
| 892 | [[self cancelledLock] unlock]; | 923 | [[self cancelledLock] unlock]; |
| 893 | 924 | ||
| 894 | if (shouldResetProgressIndicators) { | 925 | if (shouldResetProgressIndicators) { |
| @@ -919,14 +950,14 @@ static BOOL isiPhoneOS2; | @@ -919,14 +950,14 @@ static BOOL isiPhoneOS2; | ||
| 919 | 950 | ||
| 920 | [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]; | 951 | [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]; |
| 921 | 952 | ||
| 922 | - // If we're running asynchronously on the main thread, the runloop will already be running | 953 | + // If we're running asynchronously on the main thread, the runloop will already be running and we can return control |
| 923 | if (![NSThread isMainThread]) { | 954 | if (![NSThread isMainThread]) { |
| 924 | - // Will stop automatically when the request is done | 955 | + while (!complete) { |
| 925 | CFRunLoopRun(); | 956 | CFRunLoopRun(); |
| 926 | } | 957 | } |
| 958 | + } | ||
| 927 | } | 959 | } |
| 928 | 960 | ||
| 929 | - | ||
| 930 | // This is the main loop for synchronous requests. | 961 | // This is the main loop for synchronous requests. |
| 931 | - (void)loadSynchronous | 962 | - (void)loadSynchronous |
| 932 | { | 963 | { |
| @@ -935,31 +966,22 @@ static BOOL isiPhoneOS2; | @@ -935,31 +966,22 @@ static BOOL isiPhoneOS2; | ||
| 935 | [self scheduleReadStream]; | 966 | [self scheduleReadStream]; |
| 936 | } | 967 | } |
| 937 | 968 | ||
| 938 | -// if ([NSThread isMainThread]) { | 969 | + // If we don't need to track progress or throttle bandwidth, we won't bother to check up the status of the request (faster) |
| 939 | -// [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]; | 970 | + if (downloadProgressDelegate || uploadProgressDelegate || queue || [[self class] isBandwidthThrottled]) { |
| 940 | -// CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeOutSeconds, NO); | 971 | + [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(updateStatus:) userInfo:nil repeats:YES]; |
| 941 | -// | 972 | + } |
| 942 | -// } else if (!uploadProgressDelegate && !downloadProgressDelegate) { | ||
| 943 | -// CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeOutSeconds, NO); | ||
| 944 | -// [self checkRequestStatus]; | ||
| 945 | -// } else { | ||
| 946 | - | ||
| 947 | while (!complete) { | 973 | while (!complete) { |
| 948 | - [self checkRequestStatus]; | 974 | + CFRunLoopRun(); |
| 949 | - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, NO); | ||
| 950 | } | 975 | } |
| 951 | - //} | 976 | + |
| 952 | } | 977 | } |
| 953 | 978 | ||
| 954 | // This gets fired every 1/4 of a second in asynchronous requests to update the progress and work out if we need to timeout | 979 | // This gets fired every 1/4 of a second in asynchronous requests to update the progress and work out if we need to timeout |
| 955 | - (void)updateStatus:(NSTimer*)timer | 980 | - (void)updateStatus:(NSTimer*)timer |
| 956 | { | 981 | { |
| 982 | + //NSLog(@"foo"); | ||
| 957 | [self checkRequestStatus]; | 983 | [self checkRequestStatus]; |
| 958 | if ([self complete] || [self error]) { | 984 | if ([self complete] || [self error]) { |
| 959 | - if (![self error]) { | ||
| 960 | - [self willChangeValueForKey:@"isFinished"]; | ||
| 961 | - [self didChangeValueForKey:@"isFinished"]; | ||
| 962 | - } | ||
| 963 | [timer invalidate]; | 985 | [timer invalidate]; |
| 964 | CFRunLoopStop(CFRunLoopGetCurrent()); | 986 | CFRunLoopStop(CFRunLoopGetCurrent()); |
| 965 | } | 987 | } |
| @@ -1025,6 +1047,9 @@ static BOOL isiPhoneOS2; | @@ -1025,6 +1047,9 @@ static BOOL isiPhoneOS2; | ||
| 1025 | // readStream will be null if we aren't currently running (perhaps we're waiting for a delegate to supply credentials) | 1047 | // readStream will be null if we aren't currently running (perhaps we're waiting for a delegate to supply credentials) |
| 1026 | if (readStream) { | 1048 | if (readStream) { |
| 1027 | 1049 | ||
| 1050 | + // If we have a post body | ||
| 1051 | + if ([self postLength]) { | ||
| 1052 | + | ||
| 1028 | // Find out if we've sent any more data than last time, and reset the timeout if so | 1053 | // Find out if we've sent any more data than last time, and reset the timeout if so |
| 1029 | if (totalBytesSent > lastBytesSent) { | 1054 | if (totalBytesSent > lastBytesSent) { |
| 1030 | [self setLastActivityTime:[NSDate date]]; | 1055 | [self setLastActivityTime:[NSDate date]]; |
| @@ -1035,6 +1060,8 @@ static BOOL isiPhoneOS2; | @@ -1035,6 +1060,8 @@ static BOOL isiPhoneOS2; | ||
| 1035 | [self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]]; | 1060 | [self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]]; |
| 1036 | [ASIHTTPRequest incrementBandwidthUsedInLastSecond:(unsigned long)(totalBytesSent-lastBytesSent)]; | 1061 | [ASIHTTPRequest incrementBandwidthUsedInLastSecond:(unsigned long)(totalBytesSent-lastBytesSent)]; |
| 1037 | 1062 | ||
| 1063 | + } | ||
| 1064 | + | ||
| 1038 | [self updateProgressIndicators]; | 1065 | [self updateProgressIndicators]; |
| 1039 | 1066 | ||
| 1040 | } | 1067 | } |
| @@ -1458,12 +1485,12 @@ static BOOL isiPhoneOS2; | @@ -1458,12 +1485,12 @@ static BOOL isiPhoneOS2; | ||
| 1458 | if ([failedRequest didFailSelector] && [[failedRequest delegate] respondsToSelector:[failedRequest didFailSelector]]) { | 1485 | if ([failedRequest didFailSelector] && [[failedRequest delegate] respondsToSelector:[failedRequest didFailSelector]]) { |
| 1459 | [[failedRequest delegate] performSelectorOnMainThread:[failedRequest didFailSelector] withObject:failedRequest waitUntilDone:[NSThread isMainThread]]; | 1486 | [[failedRequest delegate] performSelectorOnMainThread:[failedRequest didFailSelector] withObject:failedRequest waitUntilDone:[NSThread isMainThread]]; |
| 1460 | } | 1487 | } |
| 1461 | - [self willChangeValueForKey:@"isFinished"]; | ||
| 1462 | - [self didChangeValueForKey:@"isFinished"]; | ||
| 1463 | 1488 | ||
| 1464 | if ([self mainRequest]) { | 1489 | if ([self mainRequest]) { |
| 1465 | [[self mainRequest] failWithError:[self error]]; | 1490 | [[self mainRequest] failWithError:[self error]]; |
| 1466 | } | 1491 | } |
| 1492 | + | ||
| 1493 | + [self markAsFinished]; | ||
| 1467 | } | 1494 | } |
| 1468 | 1495 | ||
| 1469 | #pragma mark parsing HTTP response headers | 1496 | #pragma mark parsing HTTP response headers |
| @@ -2258,14 +2285,12 @@ static BOOL isiPhoneOS2; | @@ -2258,14 +2285,12 @@ static BOOL isiPhoneOS2; | ||
| 2258 | if ([self needsRedirect]) { | 2285 | if ([self needsRedirect]) { |
| 2259 | return; | 2286 | return; |
| 2260 | } | 2287 | } |
| 2261 | -// long long bufferSize = 2048; | 2288 | + long long bufferSize = 16384; |
| 2262 | -// if (contentLength > 262144) { | 2289 | + if (contentLength > 262144) { |
| 2263 | -// bufferSize = 65536; | 2290 | + bufferSize = 262144; |
| 2264 | -// } else if (contentLength > 65536) { | 2291 | + } else if (contentLength > 65536) { |
| 2265 | -// bufferSize = 16384; | 2292 | + bufferSize = 65536; |
| 2266 | -// } | 2293 | + } |
| 2267 | - | ||
| 2268 | - long long bufferSize = 262144; | ||
| 2269 | 2294 | ||
| 2270 | // Reduce the buffer size if we're receiving data too quickly when bandwidth throttling is active | 2295 | // Reduce the buffer size if we're receiving data too quickly when bandwidth throttling is active |
| 2271 | // This just augments the throttling done in measureBandwidthUsage to reduce the amount we go over the limit | 2296 | // This just augments the throttling done in measureBandwidthUsage to reduce the amount we go over the limit |
| @@ -2289,7 +2314,7 @@ static BOOL isiPhoneOS2; | @@ -2289,7 +2314,7 @@ static BOOL isiPhoneOS2; | ||
| 2289 | } | 2314 | } |
| 2290 | 2315 | ||
| 2291 | 2316 | ||
| 2292 | - | 2317 | + //NSLog(@"read"); |
| 2293 | UInt8 buffer[bufferSize]; | 2318 | UInt8 buffer[bufferSize]; |
| 2294 | CFIndex bytesRead = CFReadStreamRead(readStream, buffer, sizeof(buffer)); | 2319 | CFIndex bytesRead = CFReadStreamRead(readStream, buffer, sizeof(buffer)); |
| 2295 | 2320 | ||
| @@ -2398,6 +2423,14 @@ static BOOL isiPhoneOS2; | @@ -2398,6 +2423,14 @@ static BOOL isiPhoneOS2; | ||
| 2398 | } else { | 2423 | } else { |
| 2399 | [self requestFinished]; | 2424 | [self requestFinished]; |
| 2400 | } | 2425 | } |
| 2426 | + [self markAsFinished]; | ||
| 2427 | +} | ||
| 2428 | + | ||
| 2429 | +- (void)markAsFinished | ||
| 2430 | +{ | ||
| 2431 | + [self willChangeValueForKey:@"isFinished"]; | ||
| 2432 | + [self didChangeValueForKey:@"isFinished"]; | ||
| 2433 | + CFRunLoopStop(CFRunLoopGetCurrent()); | ||
| 2401 | } | 2434 | } |
| 2402 | 2435 | ||
| 2403 | 2436 | ||
| @@ -2410,7 +2443,6 @@ static BOOL isiPhoneOS2; | @@ -2410,7 +2443,6 @@ static BOOL isiPhoneOS2; | ||
| 2410 | 2443 | ||
| 2411 | if (![self error]) { // We may already have handled this error | 2444 | if (![self error]) { // We may already have handled this error |
| 2412 | 2445 | ||
| 2413 | - | ||
| 2414 | NSString *reason = @"A connection failure occurred"; | 2446 | NSString *reason = @"A connection failure occurred"; |
| 2415 | 2447 | ||
| 2416 | // We'll use a custom error message for SSL errors, but you should always check underlying error if you want more details | 2448 | // We'll use a custom error message for SSL errors, but you should always check underlying error if you want more details |
| @@ -2424,6 +2456,7 @@ static BOOL isiPhoneOS2; | @@ -2424,6 +2456,7 @@ static BOOL isiPhoneOS2; | ||
| 2424 | 2456 | ||
| 2425 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIConnectionFailureErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:reason,NSLocalizedDescriptionKey,underlyingError,NSUnderlyingErrorKey,nil]]]; | 2457 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIConnectionFailureErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:reason,NSLocalizedDescriptionKey,underlyingError,NSUnderlyingErrorKey,nil]]]; |
| 2426 | } | 2458 | } |
| 2459 | + [self checkRequestStatus]; | ||
| 2427 | } | 2460 | } |
| 2428 | 2461 | ||
| 2429 | #pragma mark managing the read stream | 2462 | #pragma mark managing the read stream |
| @@ -24,7 +24,8 @@ | @@ -24,7 +24,8 @@ | ||
| 24 | 24 | ||
| 25 | - (void)setUp | 25 | - (void)setUp |
| 26 | { | 26 | { |
| 27 | - [self setTestURL:[NSURL URLWithString:@"http://allseeing-i.com"]]; | 27 | + [self setTestURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_%28abridged%29.txt"]]; |
| 28 | + //[self setTestURL:[NSURL URLWithString:@"http://allseeing-i.com"]]; | ||
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | - (void)testASIHTTPRequestSynchronousPerformance | 31 | - (void)testASIHTTPRequestSynchronousPerformance |
| @@ -47,7 +48,6 @@ | @@ -47,7 +48,6 @@ | ||
| 47 | [request addRequestHeader:@"Accept-Language" value:@"en/us"]; | 48 | [request addRequestHeader:@"Accept-Language" value:@"en/us"]; |
| 48 | [request setUseCookiePersistance:NO]; | 49 | [request setUseCookiePersistance:NO]; |
| 49 | [request setUseSessionPersistance:NO]; | 50 | [request setUseSessionPersistance:NO]; |
| 50 | - //[request setShouldRunInBackgroundThread:YES]; | ||
| 51 | [request startSynchronous]; | 51 | [request startSynchronous]; |
| 52 | if ([request error]) { | 52 | if ([request error]) { |
| 53 | NSLog(@"Request failed - cannot proceed with test"); | 53 | NSLog(@"Request failed - cannot proceed with test"); |
| @@ -116,7 +116,7 @@ | @@ -116,7 +116,7 @@ | ||
| 116 | [self performSelectorOnMainThread:@selector(startASIHTTPRequests) withObject:nil waitUntilDone:NO]; | 116 | [self performSelectorOnMainThread:@selector(startASIHTTPRequests) withObject:nil waitUntilDone:NO]; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | -- (void)testASIHTTPRequestAsyncPerformanceWithQueue | 119 | +- (void)testQueuedASIHTTPRequestAsyncPerformance |
| 120 | { | 120 | { |
| 121 | [self performSelectorOnMainThread:@selector(startASIHTTPRequestsWithQueue) withObject:nil waitUntilDone:NO]; | 121 | [self performSelectorOnMainThread:@selector(startASIHTTPRequestsWithQueue) withObject:nil waitUntilDone:NO]; |
| 122 | } | 122 | } |
| @@ -129,13 +129,15 @@ | @@ -129,13 +129,15 @@ | ||
| 129 | [self setTestStartDate:[NSDate date]]; | 129 | [self setTestStartDate:[NSDate date]]; |
| 130 | int i; | 130 | int i; |
| 131 | for (i=0; i<10; i++) { | 131 | for (i=0; i<10; i++) { |
| 132 | - ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]]; | 132 | + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:testURL]; |
| 133 | //Send the same headers as NSURLRequest | 133 | //Send the same headers as NSURLRequest |
| 134 | [request addRequestHeader:@"Pragma" value:@"no-cache"]; | 134 | [request addRequestHeader:@"Pragma" value:@"no-cache"]; |
| 135 | [request addRequestHeader:@"Accept" value:@"*/*"]; | 135 | [request addRequestHeader:@"Accept" value:@"*/*"]; |
| 136 | [request addRequestHeader:@"Accept-Language" value:@"en/us"]; | 136 | [request addRequestHeader:@"Accept-Language" value:@"en/us"]; |
| 137 | + [request setUseCookiePersistance:NO]; | ||
| 138 | + [request setUseSessionPersistance:NO]; | ||
| 137 | [request setDelegate:self]; | 139 | [request setDelegate:self]; |
| 138 | - [request start]; | 140 | + [request startAsynchronous]; |
| 139 | } | 141 | } |
| 140 | } | 142 | } |
| 141 | 143 | ||
| @@ -146,13 +148,17 @@ | @@ -146,13 +148,17 @@ | ||
| 146 | [self setTestStartDate:[NSDate date]]; | 148 | [self setTestStartDate:[NSDate date]]; |
| 147 | int i; | 149 | int i; |
| 148 | NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease]; | 150 | NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease]; |
| 151 | + [queue setMaxConcurrentOperationCount:4]; | ||
| 149 | for (i=0; i<10; i++) { | 152 | for (i=0; i<10; i++) { |
| 150 | - ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"]]; | 153 | + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:testURL]; |
| 151 | //Send the same headers as NSURLRequest | 154 | //Send the same headers as NSURLRequest |
| 152 | [request addRequestHeader:@"Pragma" value:@"no-cache"]; | 155 | [request addRequestHeader:@"Pragma" value:@"no-cache"]; |
| 153 | [request addRequestHeader:@"Accept" value:@"*/*"]; | 156 | [request addRequestHeader:@"Accept" value:@"*/*"]; |
| 154 | [request addRequestHeader:@"Accept-Language" value:@"en/us"]; | 157 | [request addRequestHeader:@"Accept-Language" value:@"en/us"]; |
| 158 | + [request setUseCookiePersistance:NO]; | ||
| 159 | + [request setUseSessionPersistance:NO]; | ||
| 155 | [request setDelegate:self]; | 160 | [request setDelegate:self]; |
| 161 | + [request setShouldRunInBackgroundThread:YES]; | ||
| 156 | [queue addOperation:request]; | 162 | [queue addOperation:request]; |
| 157 | } | 163 | } |
| 158 | } | 164 | } |
| @@ -185,7 +191,7 @@ | @@ -185,7 +191,7 @@ | ||
| 185 | 191 | ||
| 186 | int i; | 192 | int i; |
| 187 | for (i=0; i<10; i++) { | 193 | for (i=0; i<10; i++) { |
| 188 | - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10]; | 194 | + NSURLRequest *request = [NSURLRequest requestWithURL:testURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10]; |
| 189 | [[self responseData] addObject:[NSMutableData data]]; | 195 | [[self responseData] addObject:[NSMutableData data]]; |
| 190 | NSURLConnectionSubclass *connection = [[[NSURLConnectionSubclass alloc] initWithRequest:request delegate:self startImmediately:YES] autorelease]; | 196 | NSURLConnectionSubclass *connection = [[[NSURLConnectionSubclass alloc] initWithRequest:request delegate:self startImmediately:YES] autorelease]; |
| 191 | [connection setTag:i]; | 197 | [connection setTag:i]; |
-
Please register or login to post a comment