Joseph Heenan
Committed by Ben Copsey

Change mechanism for calling delegates to be more thread safe

The previous mechanism can end up calling a delegate that has been removed by a setDelegate:nil, and hence may already be deallocated.

Now we run a callback on the mainthread, which only dereferences the delegate/queue and selectors to be called when it runs on the main thread.

The authenticationdelegate code is still using the old method. This should be looked at separately; it is slightly more complex as it needs to know if a delegate exists to be called.
... ... @@ -508,10 +508,10 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
- (void)incrementUploadSizeBy:(long long)length;
// Helper method for interacting with progress indicators to abstract the details of different APIS (NSProgressIndicator and UIProgressView)
+ (void)updateProgressIndicator:(id)indicator withProgress:(unsigned long long)progress ofTotal:(unsigned long long)total;
+ (void)updateProgressIndicator:(id *)indicator withProgress:(unsigned long long)progress ofTotal:(unsigned long long)total;
// Helper method used for performing invocations on the main thread (used for progress)
+ (void)performSelector:(SEL)selector onTarget:(id)target withObject:(id)object amount:(void *)amount;
+ (void)performSelector:(SEL)selector onTarget:(id *)target withObject:(id)object amount:(void *)amount;
#pragma mark handling request complete / failure
... ...
This diff is collapsed. Click to expand it.
... ... @@ -11,7 +11,7 @@
// Private stuff
@interface ASINetworkQueue ()
- (void)resetProgressDelegate:(id)progressDelegate;
- (void)resetProgressDelegate:(id *)progressDelegate;
@property (assign) int requestsCount;
@end
... ... @@ -79,33 +79,33 @@
- (void)setUploadProgressDelegate:(id)newDelegate
{
uploadProgressDelegate = newDelegate;
[self resetProgressDelegate:newDelegate];
[self resetProgressDelegate:&uploadProgressDelegate];
}
- (void)setDownloadProgressDelegate:(id)newDelegate
{
downloadProgressDelegate = newDelegate;
[self resetProgressDelegate:newDelegate];
[self resetProgressDelegate:&downloadProgressDelegate];
}
- (void)resetProgressDelegate:(id)progressDelegate
- (void)resetProgressDelegate:(id *)progressDelegate
{
#if !TARGET_OS_IPHONE
// If the uploadProgressDelegate is an NSProgressIndicator, we set its MaxValue to 1.0 so we can treat it similarly to UIProgressViews
SEL selector = @selector(setMaxValue:);
if ([progressDelegate respondsToSelector:selector]) {
if ([*progressDelegate respondsToSelector:selector]) {
double max = 1.0;
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&max];
}
selector = @selector(setDoubleValue:);
if ([progressDelegate respondsToSelector:selector]) {
if ([*progressDelegate respondsToSelector:selector]) {
double value = 0.0;
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value];
}
#else
SEL selector = @selector(setProgress:);
if ([progressDelegate respondsToSelector:selector]) {
if ([*progressDelegate respondsToSelector:selector]) {
float value = 0.0f;
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value];
}
... ... @@ -153,7 +153,7 @@
[self addHEADOperation:HEADRequest];
[request addDependency:HEADRequest];
if ([request shouldResetDownloadProgress]) {
[self resetProgressDelegate:[request downloadProgressDelegate]];
[self resetProgressDelegate:&downloadProgressDelegate];
[request setShouldResetDownloadProgress:NO];
}
}
... ... @@ -168,7 +168,7 @@
}
// Tell the request not to increment the upload size when it starts, as we've already added its length
if ([request shouldResetUploadProgress]) {
[self resetProgressDelegate:[request uploadProgressDelegate]];
[self resetProgressDelegate:&uploadProgressDelegate];
[request setShouldResetUploadProgress:NO];
}
... ... @@ -229,7 +229,7 @@
{
[self setBytesDownloadedSoFar:[self bytesDownloadedSoFar]+bytes];
if ([self downloadProgressDelegate]) {
[ASIHTTPRequest updateProgressIndicator:[self downloadProgressDelegate] withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]];
[ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]];
}
}
... ... @@ -237,7 +237,7 @@
{
[self setBytesUploadedSoFar:[self bytesUploadedSoFar]+bytes];
if ([self uploadProgressDelegate]) {
[ASIHTTPRequest updateProgressIndicator:[self uploadProgressDelegate] withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]];
[ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]];
}
}
... ...