Kevin's Code
Talk is cheap, show me the code!

iOS使用Singleton控制Network Activity Indicator

Mar 31, 2013
在处理网络通讯时,为了告知用户正在使用网络,告诉他们我在费你的流量哦,不仅需要在App中设置一些对象,比如UIActivityIndicatorView,还需要在Status Bar上显示网络活动指示器(Network Activity Indicator)。

处理网络事务大多都在子线程中执行,可能使用NSOperationQueue,或者是GCD。有时候会有多个网络活动同时存在,因此判断是否所有网络活动已经完成,就成了一个必须面对的问题。不可以在我的线程中把自己的下载任务完成了,就停止Network Activity Indicator,需要确保所有其他线程中的任务也全部完成。这里介绍的方法就是使用单例。

下面创建一个KMTaskCenter类,来控制网络活动的单例。

接口文件:
#import <Foundation/Foundation.h>

@interface KMTaskCenter : NSObject

+ (KMTaskCenter *)sharedTaskCenter;
- (void)addNetworkingAction;
- (void)removeNetworkingAction;

@end
公共接口提供了三个方法,一个类方法,两个对象方法。类方法用来返回一个单例,对象方法用来控制添加或者结束一个网络活动。
实现文件:
#import "KMTaskCenter.h"

@interface KMTaskCenter ()

@property (nonatomic) NSUInteger networkingCount;

@end

@implementation KMTaskCenter

+ (KMTaskCenter *)sharedTaskCenter
{
    static KMTaskCenter *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[KMTaskCenter alloc] init];
    });
    return sharedInstance;
}
- (void)addNetworkingAction
{
    self.networkingCount++;
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
- (void)removeNetworkingAction
{
    self.networkingCount--;
    if (self.networkingCount == 0) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    }
}

@end
在实现文件中,定义了一个networkingCount属性,用来统计有多少网络活动正在进行(不对NSUInteger初始化的话,其初始值默认为0)。 返回单例的类方法内,使用GCD来控制只创建一次对象。addNetworkingAction用来增加一个网络活动,removeNetworkingAction用来删除一个网络活动,并且在网络活动为0时,停止Network Activity Indicator的动画效果。

使用时需要先调用[KMTaskCenter sharedTaskCenter]来获得一个单例,然后进行添加或者删除网络活动计数的操作。
[[KMTaskCenter sharedTaskCenter] addNetworkingAction]; // 添加一个网络活动
[[KMTaskCenter sharedTaskCenter] removeNetworkingAction]; // 删除一个网络活动
可以在一个下载活动开始前,调用添加方法,然后在下载结束后,调用删除方法。下面再附上一段实际代码。
[[KMTaskCenter sharedTaskCenter] addNetworkingAction];
NSURL *url = [NSURL URLWithString:@"www.kweima.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url
                                         cachePolicy:NSURLRequestReloadIgnoringCacheData
                                     timeoutInterval:30];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
                           if (data) {
                                NSError *parseErr = nil;
                                NSArray *list = [NSJSONSerialization JSONObjectWithData:data
                                                                                options:NSJSONReadingAllowFragments
                                                                                  error:&parseErr];
                                if (list != nil || parseErr == nil) {
                                    NSLog(@"Parsing data error.");
                                    [[KMTaskCenter sharedTaskCenter] removeNetworkingAction];
                                } else {
                                    NSLog(@"Parsing data error.");
                                    [[KMTaskCenter sharedTaskCenter] removeNetworkingAction];
                                }
                            } else {
                                NSLog(@"Fetching data error.");
                                [[KMTaskCenter sharedTaskCenter] removeNetworkingAction];
                            }
}];