Ben Copsey

Added lots of comments

Added missing setDownloadProgressDelegate to ASIHTTPRequest
... ... @@ -10,20 +10,20 @@
@interface ASIFormDataRequest : ASIHTTPRequest {
//Parameters that will be POSTed to the url
// Parameters that will be POSTed to the url
NSMutableDictionary *postData;
//Files that will be POSTed to the url
// Files that will be POSTed to the url
NSMutableDictionary *fileData;
}
#pragma mark setup request
//Add a POST variable to the request
// Add a POST variable to the request
- (void)setPostValue:(id)value forKey:(NSString *)key;
//Add the contents of a local file as a POST variable to the request
// Add the contents of a local file as a POST variable to the request
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
@end
... ...
... ... @@ -61,11 +61,11 @@
NSMutableData *body = [[[NSMutableData alloc] init] autorelease];
//Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
// Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
NSString *stringBoundary = @"0xKhTmLbOuNdArY";
if ([fileData count] > 0) {
//We need to use multipart/form-data when using file upload
// We need to use multipart/form-data when using file upload
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary]];
}
... ... @@ -73,7 +73,7 @@
[body appendData:[[NSString stringWithFormat:@"--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
//Adds post data
// Adds post data
NSData *endItemBoundary = [[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding];
NSEnumerator *e = [postData keyEnumerator];
NSString *key;
... ... @@ -87,7 +87,7 @@
}
}
//Adds files to upload
// Adds files to upload
NSData *contentTypeHeader = [[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding];
e = [fileData keyEnumerator];
i=0;
... ... @@ -97,14 +97,14 @@
[body appendData:contentTypeHeader];
[body appendData:[NSData dataWithContentsOfMappedFile:filePath]];
i++;
if (i != [fileData count]) { //Only add the boundary if this is not the last item in the post body
// Only add the boundary if this is not the last item in the post body
if (i != [fileData count]) {
[body appendData:endItemBoundary];
}
}
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
//Since we've got post data, let's set the post body to an empty NSMutableData object
[self setPostBody:body];
//Now we've created our post data, construct the request
... ...
... ... @@ -163,8 +163,13 @@
- (void)updateUploadProgress;
- (void)resetDownloadProgress:(NSNumber *)max;
- (void)updateDownloadProgress;
// Called when authorisation is needed, as we only find out we don't have permission to something when the upload is complete
- (void)removeUploadProgressSoFar;
// Helper method for interacting with progress indicators to abstract the details of different APIS (NSProgressIndicator and UIProgressView)
+ (void)setProgress:(double)progress forProgressIndicator:(id)indicator;
#pragma mark handling request complete / failure
// Called when a request completes successfully - defaults to: @selector(requestFinished:)
... ... @@ -228,8 +233,6 @@
// Dump all session data (authentication and cookies)
+ (void)clearSession;
//Helper method for interacting with progress indicators to abstract the details of different APIS for cocoa and cocoa touch
+ (void)setProgress:(double)progress forProgressIndicator:(id)indicator;
@property (retain) NSString *username;
@property (retain) NSString *password;
... ...
... ... @@ -13,6 +13,7 @@
#import "ASIHTTPRequest.h"
#import "NSHTTPCookieAdditions.h"
// We use our own custom run loop mode as CoreAnimation seems to want to hijack our threads otherwise
static CFStringRef ASIHTTPRequestRunMode = CFSTR("ASIHTTPRequest");
static NSString *NetworkRequestErrorDomain = @"com.Your-Company.Your-Product.NetworkError.";
... ... @@ -31,8 +32,7 @@ static void ReadStreamClientCallBack(CFReadStreamRef readStream, CFStreamEventTy
[((ASIHTTPRequest*)clientCallBackInfo) handleNetworkEvent: type];
}
//This lock prevents the operation from being cancelled while it is trying to update the progress, and vice versa
// This lock prevents the operation from being cancelled while it is trying to update the progress, and vice versa
static NSLock *progressLock;
@implementation ASIHTTPRequest
... ... @@ -166,7 +166,7 @@ static NSLock *progressLock;
return;
}
//If we've already talked to this server and have valid credentials, let's apply them to the request
// If we've already talked to this server and have valid credentials, let's apply them to the request
if (useSessionPersistance && sessionCredentials && sessionAuthentication) {
if (!CFHTTPMessageApplyCredentialDictionary(request, sessionAuthentication, (CFMutableDictionaryRef)sessionCredentials, NULL)) {
[ASIHTTPRequest setSessionAuthentication:NULL];
... ... @@ -174,7 +174,7 @@ static NSLock *progressLock;
}
}
//Add cookies from the persistant (mac os global) store
// Add cookies from the persistant (mac os global) store
if (useCookiePersistance) {
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:url];
if (cookies) {
... ... @@ -182,7 +182,7 @@ static NSLock *progressLock;
}
}
//Apply request cookies
// Apply request cookies
if ([requestCookies count] > 0) {
NSHTTPCookie *cookie;
NSString *cookieHeader = nil;
... ... @@ -199,14 +199,14 @@ static NSLock *progressLock;
}
//Add custom headers
// Add custom headers
NSString *header;
for (header in requestHeaders) {
CFHTTPMessageSetHeaderFieldValue(request, (CFStringRef)header, (CFStringRef)[requestHeaders objectForKey:header]);
}
//If this is a post request and we have data to send, add it to the request
// If this is a post request and we have data to send, add it to the request
if ([self postBody]) {
CFHTTPMessageSetBody(request, (CFDataRef)postBody);
postLength = [postBody length];
... ... @@ -229,7 +229,7 @@ static NSLock *progressLock;
totalBytesRead = 0;
lastBytesRead = 0;
//If we're retrying a request after an authentication failure, let's remove any progress we made
// If we're retrying a request after an authentication failure, let's remove any progress we made
if (lastBytesSent > 0 && uploadProgressDelegate) {
[self removeUploadProgressSoFar];
}
... ... @@ -273,17 +273,17 @@ static NSLock *progressLock;
[self performSelectorOnMainThread:@selector(resetUploadProgress:) withObject:[NSNumber numberWithDouble:postLength] waitUntilDone:YES];
}
//Record when the request started, so we can timeout if nothing happens
// Record when the request started, so we can timeout if nothing happens
[self setLastActivityTime:[NSDate date]];
// Wait for the request to finish
while (!complete) {
//This may take a while, so we'll release the pool each cycle to stop a giant backlog building up
// This may take a while, so we'll release the pool each cycle to stop a giant backlog of autoreleased objects building up
[pool release];
pool = [[NSAutoreleasePool alloc] init];
//See if we need to timeout
// See if we need to timeout
if (lastActivityTime && timeOutSeconds > 0) {
if ([[NSDate date] timeIntervalSinceDate:lastActivityTime] > timeOutSeconds) {
[self failWithProblem:@"Request timed out"];
... ... @@ -324,7 +324,7 @@ static NSLock *progressLock;
if (receivedData) {
[self setReceivedData:nil];
//If we were downloading to a file, let's remove it
//If we were downloading to a file, let's remove it
} else if (downloadDestinationPath) {
[outputStream close];
[[NSFileManager defaultManager] removeFileAtPath:downloadDestinationPath handler:nil];
... ... @@ -347,40 +347,11 @@ static NSLock *progressLock;
}
+ (void)setProgress:(double)progress forProgressIndicator:(id)indicator
{
SEL selector;
//Cocoa Touch: UIProgressView
if ([indicator respondsToSelector:@selector(setProgress:)]) {
selector = @selector(setProgress:);
NSMethodSignature *signature = [[indicator class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
float progressFloat = (float)progress; //UIProgressView wants a float for the progress parameter
[invocation setArgument:&progressFloat atIndex:2];
[invocation invokeWithTarget:indicator];
//Cocoa: NSProgressIndicator
} else if ([indicator respondsToSelector:@selector(setDoubleValue:)]) {
selector = @selector(setDoubleValue:);
NSMethodSignature *signature = [[indicator class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
[invocation setArgument:&progress atIndex:2];
[invocation invokeWithTarget:indicator];
//Progress indicator is some other thing that we can't handle
} else {
return;
}
}
- (void)setUploadProgressDelegate:(id)newDelegate
{
uploadProgressDelegate = newDelegate;
// If the uploadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
SEL selector = @selector(setMaxValue:);
if ([uploadProgressDelegate respondsToSelector:selector]) {
double max = 1.0;
... ... @@ -394,31 +365,20 @@ static NSLock *progressLock;
}
}
-(void)removeUploadProgressSoFar
- (void)setDownloadProgressDelegate:(id)newDelegate
{
[progressLock lock];
if ([self isCancelled]) {
[progressLock unlock];
return;
}
downloadProgressDelegate = newDelegate;
//We're using a progress queue or compatible controller to handle progress
if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) {
int value = 0-lastBytesSent;
SEL selector = @selector(incrementUploadProgressBy:);
NSMethodSignature *signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
// If the downloadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
SEL selector = @selector(setMaxValue:);
if ([downloadProgressDelegate respondsToSelector:selector]) {
double max = 1.0;
NSMethodSignature *signature = [[downloadProgressDelegate class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:uploadProgressDelegate];
[invocation setSelector:selector];
[invocation setArgument:&value atIndex:2];
[invocation invoke];
//We aren't using a queue, we should just set progress of the indicator to 0
} else {
[ASIHTTPRequest setProgress:0 forProgressIndicator:uploadProgressDelegate];
}
[progressLock unlock];
[invocation setSelector:@selector(setMaxValue:)];
[invocation setArgument:&max atIndex:2];
[invocation invokeWithTarget:downloadProgressDelegate];
}
}
... ... @@ -546,6 +506,65 @@ static NSLock *progressLock;
[progressLock unlock];
}
-(void)removeUploadProgressSoFar
{
[progressLock lock];
if ([self isCancelled]) {
[progressLock unlock];
return;
}
//We're using a progress queue or compatible controller to handle progress
if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) {
int value = 0-lastBytesSent;
SEL selector = @selector(incrementUploadProgressBy:);
NSMethodSignature *signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:uploadProgressDelegate];
[invocation setSelector:selector];
[invocation setArgument:&value atIndex:2];
[invocation invoke];
//We aren't using a queue, we should just set progress of the indicator to 0
} else {
[ASIHTTPRequest setProgress:0 forProgressIndicator:uploadProgressDelegate];
}
[progressLock unlock];
}
+ (void)setProgress:(double)progress forProgressIndicator:(id)indicator
{
SEL selector;
//Cocoa Touch: UIProgressView
if ([indicator respondsToSelector:@selector(setProgress:)]) {
selector = @selector(setProgress:);
NSMethodSignature *signature = [[indicator class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
float progressFloat = (float)progress; //UIProgressView wants a float for the progress parameter
[invocation setArgument:&progressFloat atIndex:2];
[invocation invokeWithTarget:indicator];
//Cocoa: NSProgressIndicator
} else if ([indicator respondsToSelector:@selector(setDoubleValue:)]) {
selector = @selector(setDoubleValue:);
NSMethodSignature *signature = [[indicator class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
[invocation setArgument:&progress atIndex:2];
[invocation invokeWithTarget:indicator];
//Progress indicator is some other thing that we can't handle
} else {
return;
}
}
#pragma mark handling request complete / failure
... ... @@ -718,7 +737,7 @@ static NSLock *progressLock;
- (void)attemptToApplyCredentialsAndResume
{
//Read authentication data
// Read authentication data
if (!requestAuthentication) {
CFHTTPMessageRef responseHeader = (CFHTTPMessageRef) CFReadStreamCopyProperty(readStream,kCFStreamPropertyHTTPResponseHeader);
requestAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
... ... @@ -730,7 +749,7 @@ static NSLock *progressLock;
return;
}
//See if authentication is valid
// See if authentication is valid
CFStreamError err;
if (!CFHTTPAuthenticationIsValid(requestAuthentication, &err)) {
... ... @@ -749,7 +768,7 @@ static NSLock *progressLock;
[authenticationLock lockWhenCondition:2];
[authenticationLock unlock];
//Hopefully, the delegate gave us some credentials, let's apply them and reload
// Hopefully, the delegate gave us some credentials, let's apply them and reload
[self attemptToApplyCredentialsAndResume];
return;
}
... ... @@ -768,7 +787,7 @@ static NSLock *progressLock;
[self failWithProblem:@"Failed to apply credentials to request"];
}
// are a user name & password needed?
// Are a user name & password needed?
} else if (CFHTTPAuthenticationRequiresUserNameAndPassword(requestAuthentication)) {
NSMutableDictionary *newCredentials = [self findCredentials];
... ... @@ -784,7 +803,7 @@ static NSLock *progressLock;
return;
}
//We've got no credentials, let's ask the delegate to sort this out
// We've got no credentials, let's ask the delegate to sort this out
ignoreError = YES;
if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
[delegate performSelectorOnMainThread:@selector(authorizationNeededForRequest:) withObject:self waitUntilDone:YES];
... ... @@ -794,7 +813,7 @@ static NSLock *progressLock;
return;
}
//The delegate isn't interested, we'll have to give up
// The delegate isn't interested, we'll have to give up
[self setError:[self authenticationError]];
complete = YES;
return;
... ... @@ -890,7 +909,7 @@ static NSLock *progressLock;
readStream = NULL;
}
//close the output stream as we're done writing to the file
// Close the output stream as we're done writing to the file
if (downloadDestinationPath) {
[outputStream close];
}
... ... @@ -906,7 +925,7 @@ static NSLock *progressLock;
[self cancelLoad];
if (!error) { //We may already have handled this error
if (!error) { // We may already have handled this error
[self failWithProblem:[NSString stringWithFormat: @"An error occurred: %@",[err localizedDescription]]];
}
}
... ... @@ -980,7 +999,7 @@ static NSLock *progressLock;
+ (void)setSessionCookies:(NSMutableArray *)newSessionCookies
{
//Remove existing cookies from the persistent store
// Remove existing cookies from the persistent store
NSHTTPCookie *cookie;
for (cookie in newSessionCookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
... ...
... ... @@ -20,7 +20,6 @@
- (void)testFileDownload;
- (void)testDownloadProgress;
- (void)testUploadProgress;
- (void)testOperationQueue;
- (void)testCookies;
@end
... ...
... ... @@ -138,66 +138,6 @@ More tests needed for:
{
progress = newProgress;
}
- (void)testOperationQueue
{
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
NSURL *url;
url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/first"] autorelease];
ASIHTTPRequest *request1 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[queue addOperation:request1];
url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/second"] autorelease];
ASIHTTPRequest *request2 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[queue addOperation:request2];
url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/third"] autorelease];
ASIHTTPRequest *request3 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[queue addOperation:request3];
url = [[[NSURL alloc] initWithString:@""] autorelease];
ASIHTTPRequest *request4 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[queue addOperation:request4];
url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/broken"] autorelease];
ASIHTTPRequest *request5 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[queue addOperation:request5];
[queue waitUntilAllOperationsAreFinished];
BOOL success;
success = ([request1 error] == nil);
STAssertTrue(success,@"Request 1 failed");
success = [[request1 dataString] isEqualToString:@"This is the expected content for the first string"];
STAssertTrue(success,@"Failed to download the correct data for request 1");
success = ([request2 error] == nil);
STAssertTrue(success,@"Request 2 failed");
success = [[request2 dataString] isEqualToString:@"This is the expected content for the second string"];
STAssertTrue(success,@"Failed to download the correct data for request 2");
success = ([request3 error] == nil);
STAssertTrue(success,@"Request 3 failed");
success = [[request3 dataString] isEqualToString:@"This is the expected content for the third string"];
STAssertTrue(success,@"Failed to download the correct data for request 3");
success = ([request4 error] != nil);
STAssertTrue(success,@"Request 4 succeed when it should have failed");
success = ([request5 error] == nil);
STAssertTrue(success,@"Request 5 failed");
success = ([request5 responseStatusCode] == 404);
STAssertTrue(success,@"Failed to obtain the correct status code for request 5");
}
... ...
... ... @@ -9,27 +9,44 @@
@interface ASINetworkQueue : NSOperationQueue {
// Delegate will get didFail + didFinish messages (if set), as well as authorizationNeededForRequest messages
id delegate;
// Will be called when a request completes with the request as the argument
SEL requestDidFinishSelector;
// Will be called when a request fails with the request as the argument
SEL requestDidFailSelector;
// Will be called when the queue finishes with the queue as the argument
SEL queueDidFinishSelector;
// Upload progress indicator, probably an NSProgressIndicator or UIProgressView
id uploadProgressDelegate;
// Total amount uploaded so far for all requests in this queue
int uploadProgressBytes;
// Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
int uploadProgressTotalBytes;
// Download progress indicator, probably an NSProgressIndicator or UIProgressView
id downloadProgressDelegate;
// Total amount downloaded so far for all requests in this queue
int downloadProgressBytes;
int downloadProgressTotalBytes;
SEL requestDidFinishSelector;
SEL requestDidFailSelector;
SEL queueDidFinishSelector;
// Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
int downloadProgressTotalBytes;
// When YES, the queue will cancel all requests when a request fails. Default is YES
BOOL shouldCancelAllRequestsOnFailure;
int requestsCount;
int requestsCompleteCount;
}
//
// Called at the start of a request to add on the size of this upload to the total
- (void)incrementUploadSizeBy:(int)bytes;
... ...
... ... @@ -48,6 +48,8 @@
- (void)setUploadProgressDelegate:(id)newDelegate
{
uploadProgressDelegate = newDelegate;
// If the uploadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
SEL selector = @selector(setMaxValue:);
if ([uploadProgressDelegate respondsToSelector:selector]) {
double max = 1.0;
... ... @@ -64,6 +66,8 @@
- (void)setDownloadProgressDelegate:(id)newDelegate
{
downloadProgressDelegate = newDelegate;
// If the downloadProgressDelegate is an NSProgressIndicator, we set it's MaxValue to 1.0 so we can treat it similarly to UIProgressViews
SEL selector = @selector(setMaxValue:);
if ([downloadProgressDelegate respondsToSelector:selector]) {
double max = 1.0;
... ... @@ -75,7 +79,7 @@
}
}
//Only add ASIHTTPRequests to this queue
// Only add ASIHTTPRequests to this queue!!
- (void)addOperation:(NSOperation *)operation
{
if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
... ... @@ -160,6 +164,7 @@
[ASIHTTPRequest setProgress:progress forProgressIndicator:downloadProgressDelegate];
}
// Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate
- (void)authorizationNeededForRequest:(ASIHTTPRequest *)request
{
if ([delegate respondsToSelector:@selector(authorizationNeededForRequest:)]) {
... ...
... ... @@ -82,12 +82,48 @@
url = [[[NSURL alloc] initWithString:@""] autorelease];
requestThatShouldFail = [[ASIHTTPRequest alloc] initWithURL:url];
[networkQueue addOperation:requestThatShouldFail];
url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/asi-http-request/tests/broken"] autorelease];
ASIHTTPRequest *request5 = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[networkQueue addOperation:request5];
NSDate* endDate = [NSDate distantFuture];
while (!complete) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
}
BOOL success;
success = ([request1 error] == nil);
STAssertTrue(success,@"Request 1 failed");
success = [[request1 dataString] isEqualToString:@"This is the expected content for the first string"];
STAssertTrue(success,@"Failed to download the correct data for request 1");
success = ([request2 error] == nil);
STAssertTrue(success,@"Request 2 failed");
success = [[request2 dataString] isEqualToString:@"This is the expected content for the second string"];
STAssertTrue(success,@"Failed to download the correct data for request 2");
success = ([request3 error] == nil);
STAssertTrue(success,@"Request 3 failed");
success = [[request3 dataString] isEqualToString:@"This is the expected content for the third string"];
STAssertTrue(success,@"Failed to download the correct data for request 3");
success = ([requestThatShouldFail error] != nil);
STAssertTrue(success,@"Request 4 succeed when it should have failed");
success = ([request5 error] == nil);
STAssertTrue(success,@"Request 5 failed");
success = ([request5 responseStatusCode] == 404);
STAssertTrue(success,@"Failed to obtain the correct status code for request 5");
[requestThatShouldFail release];
}
... ... @@ -118,14 +154,14 @@
url = [[[NSURL alloc] initWithString:@""] autorelease];
requestThatShouldFail = [[ASIHTTPRequest alloc] initWithURL:url];
[networkQueue addOperation:requestThatShouldFail];
NSDate* endDate = [NSDate distantFuture];
while (!complete) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];
}
[requestThatShouldFail release];
[requestThatShouldFail release];
}
- (void)requestFailedCancellingOthers:(ASIHTTPRequest *)request
... ... @@ -144,7 +180,6 @@
- (void)queueFinished:(ASINetworkQueue *)queue
{
complete = YES;
}
... ...