Skip to content

Commit

Permalink
More work on concurrent NSOperations - create thread ourselves when s…
Browse files Browse the repository at this point in the history
…tarted from a queue, but not on snowleopard
  • Loading branch information
pokeb committed Nov 25, 2009
1 parent 32fdecb commit 78233e9
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 22 deletions.
8 changes: 6 additions & 2 deletions Classes/ASIHTTPRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
BOOL shouldPresentCredentialsBeforeChallenge;

BOOL isSynchronous;

BOOL inProgress;
}

#pragma mark init / dealloc
Expand Down Expand Up @@ -358,14 +360,16 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;

#pragma mark running a request

// For an asynchronous request in the current thread, use [request start]


// Run a request asynchronously in the background by adding it to the global queue, where it will run in its own thread
- (void)startInBackgroundThread;

// Run a request synchronously in the current thread
- (void)startSynchronous;

// Run a request asynchronously in the current thread
- (void)startAsynchronous;


#pragma mark request logic
Expand Down Expand Up @@ -653,5 +657,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
@property (assign, nonatomic) BOOL haveBuiltPostBody;

@property (assign, readonly) BOOL isSynchronous;

@property (assign, readonly) BOOL inProgress;
@end
42 changes: 39 additions & 3 deletions Classes/ASIHTTPRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ + (void)recordBandwidthUsage;
@property (retain) NSString *proxyAuthenticationRealm;
@property (retain) NSString *responseStatusMessage;
@property (assign) BOOL isSynchronous;
@property (assign) BOOL inProgress;
@end


Expand Down Expand Up @@ -443,6 +444,7 @@ - (void)startInBackgroundThread

- (void)startSynchronous
{
[self setInProgress:YES];
@try {
if (![self isCancelled] && ![self complete]) {
[self setIsSynchronous:YES];
Expand All @@ -453,12 +455,39 @@ - (void)startSynchronous
NSError *underlyingError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnhandledExceptionError userInfo:[exception userInfo]];
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnhandledExceptionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[exception name],NSLocalizedDescriptionKey,[exception reason],NSLocalizedFailureReasonErrorKey,underlyingError,NSUnderlyingErrorKey,nil]]];
}
[self setInProgress:NO];
}

- (void)start
{

#if TARGET_OS_IPHONE
[self performSelectorInBackground:@selector(startAsynchronous) withObject:nil];
#else

SInt32 versionMajor;
OSErr err = Gestalt(gestaltSystemVersionMajor, &versionMajor);
if (err != noErr) {
[NSException raise:@"FailedToDetectOSVersion" format:@"Unable to determine OS version, must give up"];
}
// GCD will manage the operation in its thread pool on Snow Leopard
if (versionMajor >= 6) {
[self startAsynchronous];

// On Leopard, we'll create the thread ourselves
} else {
[self performSelectorInBackground:@selector(startAsynchronous) withObject:nil];
}
#endif
}

- (void)startAsynchronous
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// If this request is autoreleased, it will be dealloced the next time this runloop gets run
[self retain];
[self setInProgress:YES];
@try {
if ([self isCancelled] || [self complete])
{
Expand All @@ -467,13 +496,18 @@ - (void)start
} else {
[self willChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isExecuting"];


[self main];

}

} @catch (NSException *exception) {
NSError *underlyingError = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnhandledExceptionError userInfo:[exception userInfo]];
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIUnhandledExceptionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[exception name],NSLocalizedDescriptionKey,[exception reason],NSLocalizedFailureReasonErrorKey,underlyingError,NSUnderlyingErrorKey,nil]]];
}
[self setInProgress:NO];
[self release];
[pool release];
}

Expand All @@ -491,7 +525,7 @@ - (BOOL)isFinished
}

- (BOOL)isExecuting {
return ![self complete];
return [self inProgress];
}


Expand Down Expand Up @@ -1929,7 +1963,7 @@ - (BOOL)showAuthenticationDialog
// Mac authentication dialog coming soon!
#if TARGET_OS_IPHONE
// Cannot show the dialog when we are running on the main thread, as the locks will cause the app to hang
if ([self shouldPresentAuthenticationDialog] && ![NSThread isMainThread]) {
if ([self shouldPresentAuthenticationDialog]) {
[ASIAuthenticationDialog performSelectorOnMainThread:@selector(presentAuthenticationDialogForRequest:) withObject:self waitUntilDone:[NSThread isMainThread]];
[[self authenticationLock] lockWhenCondition:2];
[[self authenticationLock] unlockWithCondition:1];
Expand Down Expand Up @@ -2263,7 +2297,8 @@ - (void)handleStreamComplete
return;
}
[progressLock lock];

// Find out how much data we've uploaded so far
[self setTotalBytesSent:[[(NSNumber *)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] unsignedLongLongValue]];
[self setComplete:YES];
[self updateProgressIndicators];

Expand Down Expand Up @@ -3248,6 +3283,7 @@ + (NSString*)base64forData:(NSData*)theData {
@synthesize shouldPresentCredentialsBeforeChallenge;
@synthesize haveBuiltRequestHeaders;
@synthesize isSynchronous;
@synthesize inProgress;
@end


21 changes: 11 additions & 10 deletions Classes/Tests/ASIHTTPRequestTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,18 @@ - (void)testDelegateMethods
// Test default delegate methods
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com"]];
[request setDelegate:self];
[request start];
GHAssertTrue(started,@"Failed to call the delegate method when the request started");
GHAssertTrue(finished,@"Failed to call the delegate method when the request finished");
[request startSynchronous];

// Hacky, but this test won't run on the main thread, we have to hope the delegate methods will be called in this time
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];

request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com"]];
GHAssertTrue(started,@"Failed to call the delegate method when the request started");
GHAssertTrue(finished,@"Failed to call the delegate method when the request finished");

request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_%28abridged%29.txt"]];
[request setDelegate:self];
[request setTimeOutSeconds:0.01];
[request start];
[request startSynchronous];

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];

Expand All @@ -99,18 +100,18 @@ - (void)testDelegateMethods
[request setDelegate:self];
[request setDidStartSelector:@selector(delegateTestStarted:)];
[request setDidFinishSelector:@selector(delegateTestFinished:)];
[request start];
[request startSynchronous];

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];

GHAssertTrue(started,@"Failed to call the delegate method when the request started");
GHAssertTrue(finished,@"Failed to call the delegate method when the request finished");

request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com"]];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_%28abridged%29.txt"]];
[request setDidFailSelector:@selector(delegateTestFailed:)];
[request setDelegate:self];
[request setTimeOutSeconds:0.01];
[request start];
[request startSynchronous];

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];

Expand Down Expand Up @@ -218,7 +219,7 @@ - (void)testCharacterEncoding

- (void)testTimeOut
{
NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com"] autorelease];
NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_%28abridged%29.txt"] autorelease];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[request setTimeOutSeconds:0.0001]; //It's pretty unlikely we will be able to grab the data this quickly, so the request should timeout
[request startSynchronous];
Expand Down Expand Up @@ -414,7 +415,7 @@ - (void)testUploadProgress
[request startSynchronous];

// Wait for the progress to catch up
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];

BOOL success = (progress > 0.95);
GHAssertTrue(success,@"Failed to properly increment upload progress %f != 1.0",progress);
Expand Down
2 changes: 1 addition & 1 deletion Classes/Tests/ASINetworkQueueTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ - (void)testDelegateMethods
[networkQueue setDelegate:self];
[networkQueue setRequestDidFailSelector:@selector(delegateTestFailed:)];

request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com"]];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_%28abridged%29.txt"]];
[request setTimeOutSeconds:0.01];
[networkQueue addOperation:request];
[networkQueue go];
Expand Down
7 changes: 3 additions & 4 deletions Mac Sample/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,15 @@ - (void)imageFetch3Complete:(ASIHTTPRequest *)request
- (IBAction)fetchTopSecretInformation:(id)sender
{
[networkQueue cancelAllOperations];
[networkQueue setRequestDidFinishSelector:@selector(topSecretFetchComplete:)];
[networkQueue setDelegate:self];

[progressIndicator setDoubleValue:0];

ASIHTTPRequest *request;
request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/top_secret/"]] autorelease];
[request setDidFinishSelector:@selector(topSecretFetchComplete:)];

[request setUseKeychainPersistance:[keychainCheckbox state]];
[networkQueue addOperation:request];
[networkQueue go];
[request startAsynchronous];

}

Expand Down
2 changes: 1 addition & 1 deletion iPhone Sample/QueueViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ - (IBAction)fetchThreeImages:(id)sender
[networkQueue setDelegate:self];

ASIHTTPRequest *request;
request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/logo.png"]] autorelease];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/logo.png"]];
[networkQueue addOperation:request];

request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/i/trailsnetwork.png"]] autorelease];
Expand Down
2 changes: 1 addition & 1 deletion iPhone Sample/SynchronousViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ - (IBAction)simpleURLFetch:(id)sender
//Customise our user agent, for no real reason
[request addRequestHeader:@"User-Agent" value:@"ASIHTTPRequest"];

[request start];
[request startSynchronous];
if ([request error]) {
[htmlSource setText:[[request error] localizedDescription]];
} else if ([request responseString]) {
Expand Down

0 comments on commit 78233e9

Please sign in to comment.