问题
I have a problem with my network activity indicator in that sometimes it will continue to be displayed when it should not be.
I wrote my own manager for it and swapped it out for one that uses an NSAssert
statement like this...
- (void)setNetworkActivityIndicatorVisible:(BOOL)setVisible {
static NSInteger NumberOfCallsToSetVisible = 0;
if (setVisible)
NumberOfCallsToSetVisible++;
else
NumberOfCallsToSetVisible--;
// The assertion helps to find programmer errors in activity indicator management.
// Since a negative NumberOfCallsToSetVisible is not a fatal error,
// it should probably be removed from production code.
NSAssert(NumberOfCallsToSetVisible >= 0, @"Network Activity Indicator was asked to hide more often than shown");
// Display the indicator as long as our static counter is > 0.
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(NumberOfCallsToSetVisible > 0)];
}
I found it on SO and it has immediately pointed out that something is going wrong with my use of this function.
All of my network activity is exclusively run through a single NSOperationQueue
which is managed by a singleton class. Every operation is a subclass of NSOperation (actually a subclass of a TemplateOperation which is a subclass of NSOperation).
Anyway, all the downloads and uploads are working fine and I'm doing them all like this...
- (void)sendRequest:(NSURLRequest *)request
{
NSError *error = nil;
NSURLResponse *response = nil;
[[NetworkManager sharedInstance] setNetworkActivityIndicatorVisible:YES];
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
[[NetworkManager sharedInstance] setNetworkActivityIndicatorVisible:NO];
// other stuff...
[self processData:data];
}
The important lines are immediately before and after I send the NSURLConnection
synchronously.
Immediately before I send the request I set the network activity indicator to visible (using my manager class) and then immediately after I set it back to invisible.
Except the NSAssert has pointed out that somewhere this is not happening properly.
Could it be that running this function from multiple threads could be causing an issue? How could I solve this?
回答1:
Integer increment or decrement is not thread-safe (as far as I know), so if two threads call your method "simultaneously", the count might not get updated properly.
One solution would be to add some synchronization directive (such as @synchronized
)
to your method. Or you use the atomic increment/decrement functions:
#include <libkern/OSAtomic.h>
- (void)setNetworkActivityIndicatorVisible:(BOOL)setVisible {
static volatile int32_t NumberOfCallsToSetVisible = 0;
int32_t newValue = OSAtomicAdd32((setVisible ? +1 : -1), &NumberOfCallsToSetVisible);
NSAssert(newValue >= 0, @"Network Activity Indicator was asked to hide more often than shown");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:(newValue > 0)];
}
来源:https://stackoverflow.com/questions/16420340/fixing-my-network-activity-indicator