话不多说,直接开始代码,代码中有比较详尽的注释。
首先是对方法的封装类
ZXRequest.h
#import <Foundation/Foundation.h>
@interface ZXRequest : NSObject<NSURLConnectionDataDelegate>
{
//用来接收返回的数据
NSMutableData * _myData;
}
//先写做网络请求需要的属性
@property(nonatomic,copy)NSString * url;
//是否缓存
@property(nonatomic,assign)BOOL isCashe;
//网络请求之后调用的block
@property(nonatomic,copy)void(^finishBlock)(NSData *data);
//网络请求失败后调用的block
@property(nonatomic,copy)void(^faildBlock)();
//开始网络请求
-(void)startRequest;
@end
ZXRequest.m
#import "ZXRequest.h"
//MD5加密方式
#import "NSString+Hashing.h"
@implementation ZXRequest
//初始化方法
-(id)init{
if (self = [super init]) {
//在初始化方法里 初始化data
_myData = [[NSMutableData alloc] init];
}
return self;
}
//执行.h方法
-(void)startRequest{
//先判断是否用缓存 ,缓存里有没有数据
if (self.isCashe) {
//先把缓存的路径找到
NSString * path = [NSHomeDirectory() stringByAppendingFormat:@"tmp/%@",[self.url MD5Hash]];
//在判断当前路径下是否有文件
NSFileManager * maneger = [NSFileManager defaultManager];
//如果文件存在于path目录下
if ([maneger fileExistsAtPath:path])
{
//用path生成一个data对象 然后返回给finishBlock 然后return
NSData * data = [NSData dataWithContentsOfFile:path];
self.finishBlock(data);
return;
}
//如果没有使用缓存 或者缓存中没有数据,进行网络请求
}
NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString: self.url]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
//收到请求后做出的响应
//这里做的是打开系统的Activity控件(网络数据请求时屏幕左上角旋转的加载动画)
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
//NSURLConnection下载的数据就是这个方法中的data,不过这些数据是零散的,我们需要将这些数据拼接到我们定义的_myData中备用
[_myData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//先判断是否需要做缓存,
//若需要缓存的话,把所有返回的数据存到沙盒目录下
if (self.isCashe) {
//先找到缓存路径
NSString * path = [NSHomeDirectory() stringByAppendingFormat:@"tmp/%@",[self.url MD5Hash]];
[_myData writeToFile:path atomically:YES];
}
//还要把所有的_myData传给用到数据的类里面
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//调用代理方法(一般是处理数据)
self.finishBlock(_myData);
}
@end
通过一个管理类来使用上述的类。
只需要一个+方法即可
ZXRequestManager.h
#import <Foundation/Foundation.h>
#import "ZXRequest.h"
@interface ZXRequestManager : NSObject
+(void)requestWithURL:(NSString *)url IsCashe:(BOOL)isCache finish:(void(^)(NSData *data))finishBlock failed:(void(^)())failedBlock;
@end
ZXRequestManager.m
#import "ZXRequestManager.h"
#import "ZXRequest.h"
@implementation ZXRequestManager
+(void)requestWithURL:(NSString *)url IsCashe:(BOOL)isCache finish:(void (^)(NSData *))finishBlock failed:(void (^)())failedBlock{
//创建ZXRequst对象
ZXRequest * request = [[ZXRequest alloc] init];
request.url = url;
request.isCashe = isCache;
request.finishBlock = finishBlock;
request.faildBlock = failedBlock;
[request startRequest];
}
@end
在管理类的方法中,完成对工具类的各项属性赋值,然后在所需的地方进行调用即可。
在需要下载数据的类中写下述代码
[ZXRequestManager requestWithURL:@"网址" IsCashe:YES finish:^(NSData *data) {
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSArray * array = [dic objectForKey:@"list"];
for (NSDictionary * d in array) {
NSLog(@"%@",[d objectForKey:@"name"]);
}
} failed:^{
NSLog(@"没网滚粗");
}];
在调用时要传入的参数有 网址 是否缓存(YES or NO)
另外,还需要写两个block方法
finish:^(NSData *data){}其中写的是下载完成后对数据的处理,这里是对数据进行遍历输出
failed:^{ }其中写的是在下载失败时进行的操作。
需要注意的是,由于在这种方法下,数据是"异步下载",并不是在执行了这个方法之后就会完成了数据的下载,在此期间,如果在代码的其他地方需要用到下载来的数据,必须要将对应的处理下载finish:^(NSData *data){}的方法体中,否则会出现错误(一般是数据为空的错误)。
最后,由于在数据存储的时候采用了加密,所以需要导入一个数据加密的类。
这里提供方法的实现(转)
NSString+Hashing.h
#import <Foundation/Foundation.h>
@interface NSString (NSString_Hashing)
- (NSString *)MD5Hash;
+(NSString*)fileMD5:(NSString*)path;
+(NSString*)dataMD5:(NSData*)data;
@end
NSString+Hashing.m
#import "NSString+Hashing.h"
#import <CommonCrypto/CommonDigest.h>
@implementation NSString (NSString_Hashing)
- (NSString *)MD5Hash
{
const char *cStr = [self UTF8String];
unsigned char result[16];
CC_MD5(cStr, strlen(cStr), result);
return [NSString stringWithFormat:
@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]];
}
+(NSString*)dataMD5:(NSData*)data
{
CC_MD5_CTX md5;
CC_MD5_Init(&md5);
CC_MD5_Update(&md5, [data bytes], [data length]);
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(digest, &md5);
NSString* s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1],
digest[2], digest[3],
digest[4], digest[5],
digest[6], digest[7],
digest[8], digest[9],
digest[10], digest[11],
digest[12], digest[13],
digest[14], digest[15]];
return s;
}
+(NSString*)fileMD5:(NSString*)path
{
NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:path];
if( handle== nil ) return @"ERROR GETTING FILE MD5"; // file didnt exist
CC_MD5_CTX md5;
CC_MD5_Init(&md5);
BOOL done = NO;
while(!done)
{
NSData* fileData = [handle readDataOfLength: 10240];
CC_MD5_Update(&md5, [fileData bytes], [fileData length]);
if( [fileData length] == 0 ) done = YES;
}
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(digest, &md5);
NSString* s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1],
digest[2], digest[3],
digest[4], digest[5],
digest[6], digest[7],
digest[8], digest[9],
digest[10], digest[11],
digest[12], digest[13],
digest[14], digest[15]];
return s;
}
@end