标签:
过程
客户端(移动端)
服务器(后端)
URL
URL中常见协议
优点
原生
NSURLConnection
- 最古老的方案NSURLSession
- iOS7推出的新技术CFNetworking
- NSURL的底层,纯C语言第三方框架
ASIHttpRequest
- 外号“HTTP终结者”,功能强大,可惜已经停止更新AFNetworking
- 维护使用者多MKNetworkKit
- 印度,维护使用者少HTTP 请求
NSURLConnection
(了解即可)// 发送同步请求,会一直等待, 直到接收到数据
- (void)requestSynch
{
// 1 创建请求连接
NSURL *url = [NSURL URLWithString:@"http://www.lala.com/login?username=123&pwd=123"];
// 2 创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url ];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
// 3 发送同步请求
// endSynchronousRequest阻塞式的方法,等待服务器返回数据
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// 4.解析服务器返回的数据(解析成字符串)
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"--%@--%@-- %zd",str,response.allHeaderFields,response.statusCode);
}
// 发送异步请求
- (void)requestAsync
{
// 1 创建请求连接
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=123"];
// 2 创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url ];
// 3 发送异步请求
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// 4.解析服务器返回的数据(解析成字符串)
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSHTTPURLResponse *httpRes = (NSHTTPURLResponse* )response;
NSLog(@"--%@--%zd--%@--",str,httpRes.statusCode,httpRes.allHeaderFields);
}];
}
HTTP代理请求模式
NSURLConnectionDataDelegate
// 1 创建请求连接
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=520it&pwd=520it"];
// 2 创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url ];
// 3 代理请求模式,要遵守协议并实现代理方法
[NSURLConnection connectionWithRequest:request delegate:self];
///-----------------------------------------------------------------///
// 常用代理方法
// 接收服务器响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.localData = [NSMutableData data];
NSLog(@"-didReceiveResponse-%zd",((NSHTTPURLResponse *)response).statusCode);
}
// 接收到服务器的数据(如果数据量比较大,这个方法会被调用多次)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.localData appendData:data];
NSLog(@"-didReceiveData-");
}
// 完成数据下载
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *str = [[NSString alloc] initWithData:self.localData encoding:NSUTF8StringEncoding];
NSLog(@"-connectionDidFinishLoading-%@",str);
}
// 请求失败:请求超时等
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"-didFailWithError-");
}
- (IBAction)loginBtn:(id)sender {
// 获取控件数据和网络数据进行比对
NSString *userName = self.userText.text;
if (userName.length == 0 ) {
[SVProgressHUD showErrorWithStatus:@"用户名不能为空"];
return;
}
NSString *pwd = self.pwdText.text;
if (pwd.length == 0) {
[SVProgressHUD showErrorWithStatus:@"密码不能为空"];
return;
}
// 显示阴影
[SVProgressHUD showWithStatus:@"正在登陆中" maskType:SVProgressHUDMaskTypeBlack];
//
NSString *format = [NSString stringWithFormat:@"http://123.123.123.123/login?username=%@&pwd=%@",userName,pwd];
NSLog(@"%@",format);
// 1 创建请求连接
NSURL *url = [NSURL URLWithString:format];
// 2 创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:url ];
// 3 发送异步请求
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// JSON:{"success":"登录成功"}
// 4.解析服务器返回的数据(解析成字符串)
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// 对字符串进行分割
NSInteger loc = [str rangeOfString:@"\":\""].location + 3;
NSInteger len = [str rangeOfString:@"\"}"].location - loc;
NSString *result = [str substringWithRange:NSMakeRange(loc, len)];
// 显示结果
if ([result containsString:@"success"]) {
[SVProgressHUD showSuccessWithStatus:result];
}
else
{
[SVProgressHUD showErrorWithStatus:result];
}
}];
NSString *format = [NSString stringWithFormat:@"http://123.123.123.123/login"];
// 1 创建请求连接
NSURL *url = [NSURL URLWithString:format];
// 2 创建请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url ];
// 更改请求方法
request.HTTPMethod = @"POST";
// 设置请求体
request.HTTPBody = [@"username=520it&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];
// 设置超时
request.timeoutInterval = 5;
// 设置请求头
// [request setValue:@"ios9.0" forHTTPHeaderField:@"User-agent"];
// 3 发送请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(@"失败");
}
else
{
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
}];
format = [format stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// 设置请求体
request.HTTPBody = [@"username=小码哥&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];
JSON的格式很像OC中的字典和数组
JSON和OC的对应关系
JSON | OC |
---|---|
{ } | 字典 NSDictionry |
[] | 数组 NSArray |
“ ” | 字符串 NSString |
10,10.4 | NSNumber |
第三方
苹果原生(自带):NSJSONSerialization(性能最好)
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
// data转JSON
NSString *str = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
NSJSONReadingMutableContainers = (1UL << 0), // 可变容器
NSJSONReadingMutableLeaves = (1UL << 1), // 子节点也是可变的,也就是说转换的所有数据都是可变的
NSJSONReadingAllowFragments = (1UL << 2) // 接收零散数据,比如说单个的‘10’,‘false‘
} NS_ENUM_AVAILABLE(10_7, 5_0);
NSJSONReadingAllowFragments
使用如下 // 参数NSJSONReadingAllowFragments 用来读取单个元素
NSString *str = @"10";
NSData *data = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
NSLog(@"-- %@ --",data);
#import <MJExtension.h>
// 获得视频的模型数组
self.videos = [SLQVideo objectArrayWithKeyValuesArray:dict[@"videos"]];
// 播放视频
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123"];
// MPMoviePlayerViewController // 视图控制器
// MPMoviePlayerController // 内部没有view,不能直接弹出
MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:[url URLByAppendingPathComponent:video[@"url"]]];
// modal 出视频并播放
[self presentViewController:vc animated:YES completion:nil];
Mantle
JSONModel
MJExtension
侵入性
易用性
扩展性
XML解析方式
苹果自带:NSXMLParser
第三方库
建议
使用过程
// 初始化方法
- (instancetype)initWithContentsOfURL:(NSURL *)url; // initializes the parser with the specified URL.
- (instancetype)initWithData:(NSData *)data; // create the parser from data
// 1 使用苹果的XML类解析xml文档
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self; // 2 设置代理
[parser parse]; // 3 启动扫描
#pragma mark -NSXMLParserDelegate代理方法
// 读取文档开始
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
// NSLog(@"parserDidStartDocument");
// self.videoArray = [NSMutableArray array];
}
// 读取文档结束
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// NSLog(@"parserDidEndDocument--%@",self.videoArray);
}
// 开始读取元素,attributes 参数表示要读取的元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
// NSLog(@"didStartElement---%@",attributeDict);
// 所有的元素都会经过这里进行读取,包括根
// 所以要进行判断,把根给排除
if ([elementName isEqualToString:@"videos"]) {
return;
}
// 获取模型数据,放入数组
SLQVideoItem *video = [SLQVideoItem objectWithKeyValues:attributeDict];
[self.videoArray addObject:video];
}
// 读取元素结束
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
}
这个配置起来很麻烦
Header Search Paths
添加/usr/include/libxml2
Other Linker Flags contain
添加 -lxml2
-fno -objc -arc
使用过程
// 1 使用GDataXML解析xml文件
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
// 2 获取所有video元素,首先要获得根节点
NSArray *elements = [doc.rootElement elementsForName:@"video"];
// 3 遍历所有元素
for (GDataXMLElement *ele in elements) {
SLQVideoItem *video = [[SLQVideoItem alloc] init];
// 4 获取元素属性,转换成字符串
video.name = [[ele attributeForName:@"name"] stringValue];
video.image = [[ele attributeForName:@"image"] stringValue];
video.url = [[ele attributeForName:@"url"] stringValue];
video.length = [[[ele attributeForName:@"length"] stringValue] intValue];
[self.videoArray addObject:video];
}
// NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/weather?place=beijing&place=shanghai"];
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/weather?place=beijing,shanghai"];
@implementation NSDictionary (Log)
- (NSString *)descriptionWithLocale:(id)locale
{
// {"weathers":[{"city":"beijing,shanghai","status":"晴转多云"}]}
// 将这句话格式化输出
NSMutableString *str =[NSMutableString string];
[str appendString:@"{\n"];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// 拼接字符串
[str appendFormat:@"\t%@",key];
[str appendString:@" : "];
[str appendFormat:@"%@,\n",obj];
}];
[str appendString:@"}"];
// 取出最后一个逗号
NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[str deleteCharactersInRange:range];
}
return str;
}
@end
/*
2015-07-15 18:43:08.137 05-掌握-多值参数[65936:116425]
{
weathers : [
{
status : 晴转多云,
city : Beijing
},
{
status : 晴转多云,
city : Shanghai
}
]
}
*/
@implementation NSArray (Log)
- (NSString *)descriptionWithLocale:(id)locale
{
// 将这句话格式化输出
NSMutableString *str =[NSMutableString string];
[str appendString:@"[\n"];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[str appendFormat:@"\t%@,\n",obj];
}];
[str appendString:@"\t]"];
// 取出最后一个逗号
NSRange range = [str rangeOfString:@"," options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[str deleteCharactersInRange:range];
}
return str;
}
@end
直接使用NSData下载
NSData *data = [NSData dataWithContentsOfURL:url];
使用NSURLConnection 异步连接
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_13.png"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"---%zd---",data.length);
}];
使用NSURLConnection代理方式实现
- (void)viewDidLoad {
[super viewDidLoad];
// 建立连接
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
NSLog(@"didReceiveResponse:%@",response);
// 初始化
self.data = [NSMutableData data];
self.movieCount = [response.allHeaderFields[@"Content-Length"] integerValue];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 缓存到内存
[self.data appendData:data];
CGFloat progress = 1.0 * self.data.length / self.movieCount;
self.progressView.progress = progress;
NSLog(@"%f",progress * 100 );
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 这里进行文件的保存,保存到cache里
NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
[self.data writeToFile:[filePath stringByAppendingPathComponent:@"1.mp4"] atomically:YES];
self.data = nil;
}
// 接收到响应的时候:创建一个空的文件
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
// 获取文件长度
self.movieCount = [response.allHeaderFields[@"Content-Length"] integerValue];
// 创建一个空文件
[[NSFileManager defaultManager] createFileAtPath:SLQFilePath contents:nil attributes:nil];
// 创建文件句柄
self.handle = [NSFileHandle fileHandleForWritingAtPath:SLQFilePath];
}
// 接收到具体数据:马上把数据写入一开始创建好的文件
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 移动到文件末尾
[self.handle seekToEndOfFile];
// 写入数据
[self.handle writeData:data];
//
self.currentCount += data.length;
CGFloat progress = 1.0 * self.currentCount / self.movieCount;
self.progressView.progress = progress;
NSLog(@"%f",progress * 100 );
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.movieCount = 0;
// 关闭文件
[self.handle closeFile];
self.handle = nil;
}
SSZipArchive
// 1 使用指定文件,创建一个压缩文件
NSArray *paths = @[
@"/Users/song/Desktop/test/1.png",
@"/Users/song/Desktop/test/2.png",
@"/Users/song/Desktop/test/3.png",
@"/Users/song/Desktop/test/4.png",
@"/Users/song/Desktop/test/5.png"
];
[Main createZipFileAtPath:@"/Users/song/Desktop/test.zip" withFilesAtPaths:paths];
// 2 使用指定目录创建一个压缩文件
[Main createZipFileAtPath:@"/Users/song/Desktop/test121212.zip" withContentsOfDirectory:@"/Users/song/Desktop/test"];
// 3 解压缩一个文件到指定目录
[Main unzipFileAtPath:@"/Users/song/Desktop/test.zip" toDestination:@"/Users/song/Desktop"];
// 一定要注意这个格式是固定的
/* 文件参数格式
--分割线\r\n
Content-Disposition: form-data; name="参数名"; filename="文件名"\r\n
Content-Type: 文件的MIMEType\r\n
\r\n
文件数据
\r\n
*/
// 文件上传
// 1、创建请求
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 2、设置协议
request.HTTPMethod = @"POST";
// 3、设置请求头
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",SLQBoundary] forHTTPHeaderField:@"Content-Type"];
// 4、设置请求体
NSMutableData *body = [NSMutableData data];
// 设置文件参数
// 设置边界
[body appendData:SLQUTF(@"--")];
[body appendData:SLQUTF(SLQBoundary)];
[body appendData:SLQEnter];
// 文件参数名
[body appendData:SLQUTF([NSString[] stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"1.png\""])];
[body appendData:SLQEnter];
// 文件类型
[body appendData:SLQUTF([NSString stringWithFormat:@"Content-Type: image/png"])];
[body appendData:SLQEnter];
// 文件内容
[body appendData:SLQEnter];
UIImage *image = [UIImage imageNamed:@"1"];
[body appendData:UIImagePNGRepresentation(image)];
[body appendData:SLQEnter];
/* 非文件参数格式
--分割线\r\n
Content-Disposition: form-data; name="参数名"\r\n
\r\n
参数值
\r\n
*/
// 设置非文件参数
[body appendData:SLQUTF(@"--")];
[body appendData:SLQUTF(SLQBoundary)];
[body appendData:SLQEnter];
[body appendData:SLQUTF([NSString stringWithFormat:@"Content-Disposition: form-data; name=\"username\""])];
[body appendData:SLQEnter];
[body appendData:SLQEnter];
[body appendData:SLQUTF(@"bulabulabula")];
[body appendData:SLQEnter];
/* 结束标记
--分割--线\r\n
\r\n
*/
// 结束标记
[body appendData:SLQUTF(@"--")];
[body appendData:SLQUTF(SLQBoundary)];
[body appendData:SLQUTF(@"--")];
[body appendData:SLQEnter];
request.HTTPBody = body;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// 这个方法会调用descriptionWithLocale方法,可以在这里解决输出到控制台显示中文乱码的问题
NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
- (NSString *)getMIMEType:(NSString *)path
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]];
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
return response.MIMEType;
}
// 要包含头文件MobileCoreServices.h
+ (NSString *)mimeTypeForFileAtPath:(NSString *)path
{
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
return nil;
}
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[path pathExtension], NULL);
CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!MIMEType) {
return @"application/octet-stream";
}
return (__bridge NSString *)(MIMEType);
}
- (void)viewDidLoad {
[super viewDidLoad];
// 建立连接
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
}
/**
* 接收到响应的时候:创建一个空的文件
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
// 获取服务器那里给出的建议名字 response.suggestedFilename);
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
// 创建文件流
self.stream = [[NSOutputStream alloc] initToFileAtPath:path append:YES];
// 打开文件流
[self.stream open];
}
/**
* 接收到具体数据:马上把数据写入一开始创建好的文件
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 参数1要求是bytes
[self.stream write:[data bytes] maxLength:data.length];
NSLog(@"---");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 关闭文件流
[self.stream close];
}
// 建立连接
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_05.png"];
NSURLConnection *con = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
// 决定代理方法在哪个队列中执行
[con setDelegateQueue:[[NSOperationQueue alloc] init]];
// 开启子线程runloop
self.runloop = CFRunLoopGetCurrent();
CFRunLoopRun();
在代理方法中使用完毕,停止runloop
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"--connectionDidFinishLoading--%@",[NSThread currentThread]);
CFRunLoopStop(self.runloop);
}
NSURLSession
主要由两部分组成,一个是Session实例对象,一个是任务。使用步骤
dataTaskWithRequest
),启动task(resume
)NSURLSessionDataTask
、NSURLSessionDownloadTask
、NSURLSessionUploadTask
)NSURLSession
代理
<NSURLSessionDataDelegate>
实现过程
didReceivedResponse
didReceivedData
didComplete
大文件断点下载
NSURLSession
的方法:suspend、resume、cancel
resumeData
保存暂停时程序数据状态,取消任务后要根据状态恢复下载何为断点下载
上传
NSURLSessionUploadTast
methodBody
为上传的参数fromData
NSURLSessionConfiguration
统一配置(比如可以在这里设置是否允许设置程序使用蜂窝移动网络)NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324"];
// 1 获得NSURLSession单例对象
NSURLSession *session = [NSURLSession sharedSession];
// 2 创建任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// 4 处理数据
NSLog(@"----%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
// 3 启动任务
[task resume];
// post请求
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324"];
// 获得NSURLSession单例对象
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求头
request.HTTPMethod = @"POST";
// 设置请求体
NSMutableData *body = [NSMutableData data];
[body appendData:[@"username=123&pwd=234" dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
// 创建任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"----%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
// 启动任务
[task resume];
downloadTaskWithURL:url
进行下载,不过下载成功的文件是放在tmp临时目录里面的,一定要及时把文件给移出来。NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
// 获得NSURLSession单例对象
NSURLSession *session = [NSURLSession sharedSession];
// 创建任务
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
// 这个方式下载的文件在tmp文件夹下,要把下载的文件移动到cache中永久保存,参数是 fileURLWithPath,看清了
// loaction 表示在本地临时存储区的路径
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
}];
// 启动任务
[task resume];
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
// 创建
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
// 创建任务
NSURLSessionDataTask *task = [session dataTaskWithURL:url];
// 启动任务
[task resume];
}
// 接收服务器响应,必须手动执行后续的执行方式(允许接收数据还是不允许接收)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
NSLog(@"%s",__func__);
// 必须手动指定接下来的数据要不要接收
completionHandler(NSURLSessionResponseAllow);
}
// 接收数据,多次调用
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
NSLog(@"%s",__func__);
}
// 下载完毕后调用,如果失败,看参数error的值
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
NSURLSessionResponseCancel = 0,/* Cancel the load, this is the same as -[task cancel] */
NSURLSessionResponseAllow = 1,/* Allow the load to continue */
NSURLSessionResponseBecomeDownload = 2,/* Turn this request into a download */
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
NSURLSession
,使用dataWithTask来进行下载,并且手动控制器下载文件的去向。- (NSURLSessionDataTask *)dataTask
{
if (!_dataTask) {
// 获取下载进度,直接从沙盒中读取文件长度
NSInteger total = [[NSMutableDictionary dictionaryWithContentsOfFile:SLQDownloadFilePath][SLQFileName] integerValue];
NSInteger current = [[[NSFileManager defaultManager] attributesOfItemAtPath:SLQFilePath error:nil][NSFileSize] integerValue];
if (total && total == current ) {
NSLog(@"已经下载完毕");
return nil;
}
// 如果长度和
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/resources/videos/minion_02.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 指定要从服务器获取的数据的范围
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",current];
[request setValue:range forHTTPHeaderField:@"Range"];
// 创建任务
_dataTask = [self.session dataTaskWithRequest:request];
}
return _dataTask;
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
// NSLog(@"----%@",[response class]);
// 开启输出流
[self.stream open];
// 计算总得数据长度,response会返回请求的数据长度,不包括已经下载的数据长度,所以要累加起来
self.totalCount = [response.allHeaderFields[@"Content-Length"] integerValue] + SLQFileLength;
NSString *name = response.suggestedFilename;
// 存储总长度,将所要下载的文件长度保存起来
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:SLQDownloadFilePath];
if (dict == nil) {
dict = [NSMutableDictionary dictionary];
}
dict[SLQFileName] = @(self.totalCount);
[dict writeToFile:SLQDownloadFilePath atomically:YES];
// 继续下载
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
// 写入数据到沙盒
[self.stream write:[data bytes]maxLength:data.length];
// 获取下载进度,直接从沙盒中读取文件长度
NSLog(@"---%f",1.0 * SLQFileLength / self.totalCount);
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
// 清空
self.dataTask = nil;
[self.stream close];
self.stream = nil;
}
// 一定要注意这个格式是固定的
/* 文件参数格式
--分割线\r\n
Content-Disposition: form-data; name="file"; filename="文件名"\r\n
Content-Type: 文件的MIMEType\r\n
\r\n
文件数据
\r\n
// 结束标记
\r\n
--分割线--\r\n
\r\n
*/
// 主要是参数第二个参数要传入 **`请求体`**
[[self.session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"---%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}] resume];
GET\POST
AFHTTPRequestManager
AFHTTPSessionManager
- (void)GET
{
// GET
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
// 将数据作为参数传入
NSDictionary *dict = @{
@"username":@"12",
@"pwd":@"13"
};
[mgr GET:[NSString stringWithFormat:@"http://123.123.123.123/login"] parameters:dict success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"success:%@",responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"failure:%@",error);
}];
}
- (void)POST
{
// POST
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
// 将数据作为参数传入
NSDictionary *dict = @{
@"username":@"12",
@"pwd":@"13"
};
[mgr POST:[NSString stringWithFormat:@"http://123.123.123.123/login"] parameters:dict success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"success:%@",responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"failure:%@",error);
}];
}
- (void)upload
{
// 文件上传
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
// 将数据作为参数传入
[mgr POST:@"http://123.123.123.123/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// formdata 为要上传的数据
// [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/song/Desktop/test.png"] name:@"file" error:nil];
[formData appendPartWithFileData:[NSData dataWithContentsOfFile:@"/Users/song/Desktop/test.png"] name:@"file" fileName:@"wer.png" mimeType:@"image/png"];
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"success:%@",responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"failure:%@",error);
}];
}
文件下载
- (void)download
{
// 下载
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
[[mgr downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://123.123.123.123/resources/images/minion_02.png"]] progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
// 下载文件需要返回一个保存路径,还需要手动启动resume
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
return [NSURL fileURLWithPath:[path stringByAppendingPathComponent:response.suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(@"%@",filePath.path);
}] resume];
}
默认是解析json,如果想解析xml,需要指定管理器的解析器为xml
responseSerializer
属性设置为ADHTTPResonseSericlizer
,服务器返回什么就接受什么类型的数据。-(void)returnType
{
// 默认返回的数据时JSON,如果想返回XML,设置属性responseSerializer
// 如果想返回服务器上文件本来的类型,设置AFHTTPResponseSerializer
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
// responseSerializer 用来解析服务器返回的数据
mgr.responseSerializer = [AFHTTPResponseSerializer serializer]; // 直接使用“服务器本来返回的数据”,不做任何解析
// 告诉AFN,以XML形式解析服务器返回的数据
// mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];
// 将数据作为参数传入
[mgr GET:[NSString stringWithFormat:@"http://123.123.123.123/resources/images/minion_02.png"] parameters:nil success:^(NSURLSessionDataTask *task,id response) {
NSLog(@"success:%zd",[response length]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"failure:%@",error);
}];
}
- 手机联网状态:`AFNetWorkReachabityManager`
- 苹果自带:`Reachability` ,通过通知监听系统状态
AFNetWorkReachabityManager
- (void)monitor
{
// 监控网络状态
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
// 网络状态改变就会调用这个block
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(@"网络状态改变:%zd",status);
}];
// 打开监听器
[mgr startMonitoring];
/*
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1, // 未知
AFNetworkReachabilityStatusNotReachable = 0, // 未联网
AFNetworkReachabilityStatusReachableViaWWAN = 1, // 蜂窝网络
AFNetworkReachabilityStatusReachableViaWiFi = 2, // wifi
};
*/
}
手机联网状态:Reachability
/**通知*/
@property (nonatomic, strong) Reachability *reach;
- (void)viewDidLoad
{
[super viewDidLoad];
// 添加通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNetworkStatus) name:kReachabilityChangedNotification object:nil];
// 接收通知
self.reach = [Reachability reachabilityForInternetConnection];
[self.reach startNotifier];
}
- (void)getNetworkStatus
{
/*
typedef enum : NSInteger {
NotReachable = 0, // 网络不可知
ReachableViaWiFi, // WIFI
ReachableViaWWAN // 移动网络
} NetworkStatus;
*/
// 获取手机网络状态
if([Reachability reachabilityForLocalWiFi].currentReachabilityStatus != NotReachable)
{
NSLog(@"wifi");
}
else if([Reachability reachabilityForInternetConnection].currentReachabilityStatus != NotReachable)
{
NSLog(@"3G?4G");
}
else
{
NSLog(@"Nothing at all!");
}
}
- (void)dealloc
{
// 停止监听器
[self.reach startNotifier];
// 移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}
使用:主要是对用户的敏感信息进行加密
MD5改进
使用https要实现代理方法 didReceiveChallenge
1 创建HTTPS链接
_dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
didReceiveChallenge
/** 代理方法
* challenge : 挑战、质询
* completionHandler : 通过调用这个block,来告诉URLSession要不要接收这个证书
*/
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
// NSURLSessionAuthChallengeDisposition : 如何处理这个安全证书
// NSURLCredential :安全证书
// NSLog(@"%@",challenge);
if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
return;
}
if(completionHandler)
{
// 利用这个block说明使用这个证书
completionHandler(NSURLSessionAuthChallengeUseCredential,challenge.proposedCredential);
}
}
代理方法<UIWebViewDelegate>
shouldStartLoadWithRequest
: 请求之前判断是否允许访问(过滤某些网址)loadHTMLString
loadData:
scalesPageToFit
屏幕自适应dataDetectorTypes
自动检测网页中出现的电话号码,网址等,添加下划线和链接。// 始发送请求(加载数据)时调用这个方法
- (void)webViewDidStartLoad:(UIWebView *)webView;
// 请求完毕(加载数据完毕)时调用这个方法
- (void)webViewDidFinishLoad:(UIWebView *)webView;
// 请求错误时调用这个方法
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
// UIWebView在发送请求之前,都会调用这个方法,如果返回NO,代表停止加载请求,返回YES,代表允许加载请求
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
/*
* 每当webView即将发送一个请求之前,都会调用这个方法
* 返回YES:允许加载这个请求
* 返回NO:禁止加载这个请求
*/
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSLog(@"%s",__func__);
if ([request.URL.absoluteString containsString:@"life"]) {
return NO;
}
return YES;
}
常用JS函数
-alert(10); // 弹框
document.getElementById(‘test’); // 根据ID获得某个DOM元素
oc执行js
stringByEvaluatingJavaScriptFromString
function
JS执行OC
shouldStartLoadWithRequest
loaction.href = ‘slq://sendMessage_?参数1&参数2‘;
stringByEvaluatingJavaScriptFromString
[webView stringByEvaluatingJavaScriptFromString:@"alert(100)"];
// 调用JS中的函数,
NSLog(@"%@",[webView stringByEvaluatingJavaScriptFromString:@"login();"]);
self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title;"];
通过代理法方法 shouldStartLoadWithRequest
无参数传递
/**
* 通过这个方法完成JS调用OC
* JS和OC交互的第三方框架:WebViewJavaScriptBridge
*/
// location.href = ‘slq://call‘;
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//
NSLog(@"%@",request.URL);
NSString *url = request.URL.absoluteString;
NSString *pre = @"slq://";
if([url hasPrefix:pre])
{
// 调用OC方法
// NSLog(@"调用OC方法");
NSString *method = [url substringFromIndex:pre.length];
// NSSelectorFromString 将字符串转换成方法名
[self performSelector:NSSelectorFromString(method) withObject:nil];
return NO;
}
// NSLog(@"发送请求");
return YES;
}
2个参数
// location.href = ‘slq://call2_number2_?&100‘;
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = request.URL.absoluteString;
NSString *pre = @"slq://";
if([url hasPrefix:pre])
{
// 调用OC方法
NSString *method = [url substringFromIndex:pre.length];
// method = call2_number2_?200&300
// 分割字符串
NSArray *arr = [method componentsSeparatedByString:@"?"];
// call2:number2:
NSString *methodName = [[arr firstObject] stringByReplacingOccurrencesOfString:@"_" withString:@":"];
// 200&300
NSString *paramStr = [arr lastObject];
NSArray *params = nil;
if (arr.count == 2 && [paramStr containsString:@"&"]) {
params = [paramStr componentsSeparatedByString:@"&"];
}
NSString *param1 = [params firstObject];
NSString *param2 = params.count <= 1 ? nil : [params lastObject];
NSLog(@"%@",methodName);
[self performSelector:NSSelectorFromString(methodName) withObject:param1 withObject:param2]; // 两个参数
// [self performSelector:NSSelectorFromString(methodName) withObject:para];// 一个参数
return NO;
}
return YES;
}
3个参数
- (id)performSelector:(SEL)selector withObjects:(NSArray *)params
{
// 设置方法签名
NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:selector];
//
if (sig == nil) {
NSLog(@"方法没找到");
}
// NSInvocation 包装对象利用一个NSInvocation对象包装一次方法调用(方法调用者、方法名、方法参数、方法返回值)
NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sig];
invo.target = self;
invo.selector = selector;
// 设置参数
NSInteger paramNum = sig.numberOfArguments - 2; // 包含两个隐含参数:self and _cmd
// 取最小值作为参数,
paramNum = MIN(paramNum, params.count);
for (int i = 0 ; i < paramNum; i ++) {
id obj = params[i];
if ([obj isKindOfClass:[NSNull class]]) {
continue;
}
[invo setArgument:&obj atIndex:i + 2]; // 从第三个参数开始
}
// 设置回调
[invo invoke];
// 返回值
id returnVal = 0;
if (sig.methodReturnLength) {
[invo getReturnValue:&returnVal];
}
return returnVal;
}
void handleException(NSException *exception)
{
[[UIApplication sharedApplication].delegate performSelector:@selector(handle)];
}
- (void)handle
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"哈哈" message:@"崩溃了把" delegate:self cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];
[alertView show];
// 重新启动RunLoop
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(@"-------点击了好的");
exit(0);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 设置捕捉异常的回调
NSSetUncaughtExceptionHandler(handleException);
return YES;
}
// 去除Xcode编译警告
//#pragma clang diagnostic push // 开始
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
//#pragma clang diagnostic pop // 结束
@throw
@try @catch @finally
标签:
原文地址:http://www.cnblogs.com/pb89/p/4715135.html