本片博文里,对部分比较常用的功能做了简单的介绍,至于底层的原理,本人目前能力有限,只能略知一二,网上关于这方面的资料少到又少,千篇一律( 原文地址: http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit ).
可能这些对于 大牛 来说真的是 小菜一碟 ,所以, 强烈要求路过的高手驻扎片刻,对小生指引一番 !
MKNetworkKit的主要特点:
1.网络共享队列单例化:整个程序中只有一个主队列
2.正确显示网络状态指示
3.自动控制并发操作数:MKNetworkKit会根据网络情况自动修改并发数
4.自动缓存:MKNetworkKit能根据两次GET请求是否相同而选择是否缓存请求
5.请求冻结:当网络状态不佳时,会自动冷冻请求,等待网络情况好转时自动恢复,再次请求
6.完全支持ARC
详解:
1.网络共享队列单例化
// Network Queue is a shared singleton object.
// no matter how many instances of MKNetworkEngine is created, there is one and only one network queue
// In theory an app should contain as many network engines as the number of domains it talks to
MKNetworkEngine.m
#pragma mark Initialization
staticNSOperationQueue *_sharedNetworkQueue;
+(void) initialize
{
if(!_sharedNetworkQueue)
{
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedNetworkQueue = [[NSOperationQueue alloc] init];
//添加观察者,观察operationCount,
[_sharedNetworkQueue addObserver:[self self] forKeyPath:@"operationCount" options:0 context:NULL]; [_sharedNetworkQueue setMaxConcurrentOperationCount:6];
});
}
}
2 .正确显示网络状态显示
MKNetworkKit则由于使用了单例的共享队列,能自动显示网络状态。
在共享队列中有一个线程通过 KVO 方式会随时观察 operationCount 属性。
因此对于开发者,一般情况下根本不需要操心网络状态的显示。
MKNetworkEngine类在运行时的特性initialize(见1),在方法体里边,观察 operationCount,该值改变时,调用下面方法MKNetworkEngine.m
#pragma mark KVO for network Queue
//通过KVO监测operationCount
//实现:
+ (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == _sharedNetworkQueue && [keyPath isEqualToString:@"operationCount"]){
[[NSNotificationCenter defaultCenter] postNotificationName:kMKNetworkEngineOperationCountChangedobject:[NSNumber numberWithInteger:(NSInteger)[_sharedNetworkQueue operationCount]]];
#if TARGET_OS_IPHONE
[UIApplication sharedApplication].networkActivityIndicatorVisible = ([_sharedNetworkQueue.operations count] > 0);
#endif
}else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];}
}
3.自动控制最大并发数
绝大部分移动网络不允许 2 个以上的并发连接,因此你的队列大小在3G 网络下应当设置为 2。
MKNetworkKit 会自动为你处理好这个。
当网络出于3G/EDGE/GPRS 时,它会将并发数调整到 2。
当网络处于 Wifi 网络时,则自动调整到 6。
当然MKNetworkKit会根据网络状态的改变对最大并发数进行修改.
//reachability改变时,调用,用于修改最大并发数
#pragma mark -
#pragma mark Reachability related
-(void) reachabilityChanged:(NSNotification*) notification
{
if([self.reachabilitycurrentReachabilityStatus] == ReachableViaWiFi)
{
DLog(@"Server [%@] is reachable via Wifi",self.hostName);
[_sharedNetworkQueuesetMaxConcurrentOperationCount:6];
[selfcheckAndRestoreFrozenOperations];
}
elseif([self.reachabilitycurrentReachabilityStatus] == ReachableViaWWAN)
{
if(self.wifiOnlyMode) {
DLog(@" Disabling engine as server [%@] is reachable only via cellular data.",self.hostName);
[_sharedNetworkQueuesetMaxConcurrentOperationCount:0];
} else {
DLog(@"Server [%@] is reachable only via cellular data",self.hostName);
[_sharedNetworkQueuesetMaxConcurrentOperationCount:2];
[selfcheckAndRestoreFrozenOperations];
}
}
elseif([self.reachabilitycurrentReachabilityStatus] == NotReachable)
{
DLog(@"Server [%@] is not reachable",self.hostName);
[selffreezeOperations];
}
if(self.reachabilityChangedHandler) {
self.reachabilityChangedHandler([self.reachabilitycurrentReachabilityStatus]);
}
}
4.使用缓存
MKNetworkKit 能自动缓存你所有的 GET 请求。
当你再次发起同样的请求时,MKNetworkKit 随即就能调用 response缓存(如果可用的话)传递给 handler 进行处理。当然,它同时也向服务器发出请求。
一旦获得服务器数据,handler 被再次要求处理新获取的数据。
也就是说,你不用手动缓存。你只需要使用:
[[MKNetworkEngine sharedEngine] useCache]; 当然,你可以覆盖这个方法(子类化),定制你的缓存路径和缓存占用的内存开销 |
MKNetworkEngine.m文件
-(void) useCache {
self.memoryCache = [NSMutableDictionarydictionaryWithCapacity:[selfcacheMemoryCost]];
self.memoryCacheKeys = [NSMutableArrayarrayWithCapacity:[selfcacheMemoryCost]];
self.cacheInvalidationParams = [NSMutableDictionarydictionary];
NSString *cacheDirectory = [selfcacheDirectoryName];
//cacheDirectory = /Users/apple/Library/Application Support/iPhone Simulator/6.1/Applications/550AF26D-174B-42E6-881B-B7499FAA32B7/Documents
BOOL isDirectory =YES;
//测试文件是不是目录
BOOL folderExists = [[NSFileManagerdefaultManager] fileExistsAtPath:cacheDirectoryisDirectory:&isDirectory] && isDirectory;
if (!folderExists)
{
NSError *error =nil;
// 1,path:所要创建文件夹的路径。
//2,createIntermediates:所要创建的目录的父目录等相关的目录可能并不存在。如果想要把相关目录一起创建了,就把这个参数设成YES,否则设成NO。设成NO的话,假如父目录不存在,函数就会失败,函数返回值就是NO。
//3,attributes:这个参数就是创建目录时的一些选项设置,所有可以配置项的键可以在这里找到。一般设成nil就行了。采用默认的设置。
//4,error:函数执行错误时返回的错误对象,注意应返回的是一个地址;
[[NSFileManagerdefaultManager] createDirectoryAtPath:cacheDirectorywithIntermediateDirectories:YESattributes:nilerror:&error];
}
//添加扩展名
NSString *cacheInvalidationPlistFilePath = [cacheDirectorystringByAppendingPathExtension:@"plist"];
BOOL fileExists = [[NSFileManagerdefaultManager] fileExistsAtPath:cacheInvalidationPlistFilePath];
if (fileExists)
{
self.cacheInvalidationParams = [NSMutableDictionarydictionaryWithContentsOfFile:cacheInvalidationPlistFilePath];
}
...}
5.冻结操作
* Only POST, PUT and DELETE operations are freezable.
*In short, any operation that changes the state of the server are freezable, creating a tweet, checking into a new location etc., Operations like fetching a list of tweets (think readonly GET operations) are not freezable.*MKNetworkKit doesn't freeze (readonly) GET operations even if they are marked as freezable
*/
-( void ) enqueueOperation:( MKNetworkOperation *) operation forceReload:( BOOL ) forceReload
{
...
// 如果当前的网络状态 =NotReachable, 冻结操作
if([self.reachability currentReachabilityStatus] == NotReachable)
[self freezeOperations];
}