网络 基本概念
客户端:client
服务器:server
请求:request
响应:response
过程
客户端 -> 发送请求 -> 服务器(连接数据库)
服务器 -> 发送响应 -> 客户端
客户端(移动端)
服务器(后端)
后台
Java、PHP、.NET
远程服务器-面向所有用户(上线)
本地服务器-面向公司内部(测试)
URL
URL的全称是Uniform Resource Locator(统一资源定位符)
通过1个URL,能找到互联网上唯一的1个资源
URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL
URL的基本格式 = 协议://主机地址/路径
URL中常见协议
HTTP - 网络所有资源(http://)这个最常用
file - 本机资源(file://)
mailto - 邮件地址 (mailto:)
FTP - 网络文件资源 (ftp://)
HTTP通信
http的作用是统一客户端和服务器的数据交换格式,使得彼此可以理解。
优点
简单快速,服务器规模小,通信速度快
灵活,允许传输任意类型的数据
HTTP 0.9和1.0使用短连接方式(非持续连接):每次连接只处理一个请求,服务器做出响应后,马上断开连接。
iOS中常用的HTTP请求方式
原生
NSURLConnection
- 最古老的方案
NSURLSession
- iOS7推出的新技术
CFNetworking
- NSURL的底层,纯C语言
第三方框架
ASIHttpRequest
- 外号“HTTP终结者”,功能强大,可惜已经停止更新
AFNetworking
- 维护使用者多
MKNetworkKit
- 印度,维护使用者少
HTTP 请求
HTTP/1.1 中定义了8种方法
GET 、POST 、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
最常用的就是GET、POST
HTTP 实践 - NSURLConnection
(了解即可)
- (void )requestSynch { NSURL *url = [NSURL URLWithString:@"http://www.lala.com/login?username=123&pwd=123" ]; NSURLRequest *request = [NSURLRequest requestWithURL:url ]; NSHTTPURLResponse *response = nil ; NSError *error = nil ; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding ]; NSLog (@"--%@--%@-- %zd" ,str,response.allHeaderFields,response.statusCode); }
- (void )requestAsync { NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=123" ]; NSURLRequest *request = [NSURLRequest requestWithURL:url ]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding ]; NSHTTPURLResponse *httpRes = (NSHTTPURLResponse * )response; NSLog (@"--%@--%zd--%@--" ,str,httpRes.statusCode,httpRes.allHeaderFields); }]; }
HTTP代理请求模式
协议:NSURLConnectionDataDelegate
实现方法
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=520it&pwd=520it" ]; NSURLRequest *request = [NSURLRequest requestWithURL:url ]; [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); NSURL *url = [NSURL URLWithString:format]; NSURLRequest *request = [NSURLRequest requestWithURL:url ]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 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" ]; NSURL *url = [NSURL URLWithString:format]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url ]; request.HTTPMethod = @"POST" ; request.HTTPBody = [@"username=520it&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding ]; request.timeoutInterval = 5 ; [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 ];
POST:在设置请求体时直接设置了编码格式,会自动转换
request.HTTPBody = [@"username=小码哥&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding ];
解析JSON
服务器返回给客户端的数据一般都是JSON或者XML
JSON的格式很像OC中的字典和数组
{“name” : “jack”, “age” : 10}
{“names” : [“jack”, “rose”, “jim”]}
标准JSON格式的注意点:key必须用双引号
JSON和OC的对应关系
JSON
OC
{ }
字典 NSDictionry
[]
数组 NSArray
“ ”
字符串 NSString
10,10.4
NSNumber
IOS中JSON解决方案
第三方
JSONKit、SBJson、TouchJSON(性能从左到右,越差)
苹果原生(自带):NSJSONSerialization(性能最好)
NSJSONSerialization
+ (id )JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions )opt error:(NSError **)error; NSString *str = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions
+ (NSData *)dataWithJSONObject:(id )obj options:(NSJSONWritingOptions )opt error:(NSError **)error;
typedef NS_OPTIONS (NSUInteger , NSJSONReadingOptions ) { NSJSONReadingMutableContainers = (1 UL << 0 ), NSJSONReadingMutableLeaves = (1 UL << 1 ), NSJSONReadingAllowFragments = (1 UL << 2 ) } NS_ENUM_AVAILABLE (10 _7, 5 _0);
参数NSJSONReadingAllowFragments
使用如下
NSString *str = @"10" ;NSData *data = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding ] options:NSJSONReadingAllowFragments error:nil ];NSLog (@"-- %@ --" ,data);
JSON转模型
每次都手动去转换的话,非常费时费力。可以使用第三方框架
MJExtension
#import <MJExtension.h> self .videos = [SLQVideo objectArrayWithKeyValuesArray:dict[@"videos" ]];
苹果自带的movie播放器
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123" ]; MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:[url URLByAppendingPathComponent:video[@"url" ]]]; [self presentViewController:vc animated:YES completion:nil ];
字典转模型框架
Mantle
JSONModel
MJExtension
设计框架需要考虑的问题
解析XML
XML解析方式
苹果自带:NSXMLParser
第三方库
libxml2 : 纯C语言,默认包含在iOS SDK 中,,同时支持SAX、DOM
GDataXML : DOM方式,由google开发,基于libxml2
建议
大文件 : NSXMLParser、libxml2
小文件 : GDataXML、XSXMLParser、libxml2
XSXMLParser
使用过程
1、设置源,初始化一个XSXMLParser对象
2、设置代理,实现代理方法
3、启动扫描
- (instancetype )initWithContentsOfURL:(NSURL *)url; - (instancetype )initWithData:(NSData *)data;
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];parser.delegate = self ; [parser parse];
#pragma mark -NSXMLParserDelegate代理方法 - (void )parserDidStartDocument:(NSXMLParser *)parser { } - (void )parserDidEndDocument:(NSXMLParser *)parser { } - (void )parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)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 { }
格式化服务器返回的JSON数据
GDataXML
这个配置起来很麻烦
首先不支持CocoaPods,所以只能手动拖拽进项目,而且项目比较旧。
然后进入工程设置 Header Search Paths
添加/usr/include/libxml2
设置工程 Other Linker Flags contain
添加 -lxml2
改变文件的编译方式为非ARC - -fno -objc -arc
最后编译才不会出错
使用过程
GDataXMLDocument - 整个文档
GDataXMLElement - xml中某个元素
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil ]; NSArray *elements = [doc.rootElement elementsForName:@"video" ];for (GDataXMLElement *ele in elements) { SLQVideoItem *video = [[SLQVideoItem alloc] init]; 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,shanghai" ];
解决输出到控制台显示中文乱码的问题
重写descriptionWithLocale方法,这二个方法会在转换JSON时自动调用。
@implementation NSDictionary (Log )- (NSString *)descriptionWithLocale:(id )locale { 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 @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
文件下载 小文件下载
- (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 { 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 ; }
解压缩
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]; [Main createZipFileAtPath:@"/Users/song/Desktop/test121212.zip" withContentsOfDirectory:@"/Users/song/Desktop/test" ]; [Main unzipFileAtPath:@"/Users/song/Desktop/test.zip" toDestination:@"/Users/song/Desktop" ];
文件上传
NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/upload" ];NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];request.HTTPMethod = @"POST" ; [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@" ,SLQBoundary] forHTTPHeaderField:@"Content-Type" ]; 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]; [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]; [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) { NSLog (@"%@" ,[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil ]); }];
获取MIMEType
- (NSString *)getMIMEType:(NSString *)path { NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]; NSURLResponse *response = nil ; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil ]; return response.MIMEType; }
+ (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); }
NSOutputStream
文件流,文件输出流,可以输出到内存、硬盘、NSData
- (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 { 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 { [self .stream write:[data bytes] maxLength:data.length]; NSLog (@"---" ); } - (void )connectionDidFinishLoading:(NSURLConnection *)connection { [self .stream close]; }
NSURLConnection和NSRunLoop
使用NSURLConnection创建的请求,其内部和NSRunLoop有关联,必须保证NSRunLoop处于运行状态,否则代理方法运行起来就会出问题。
如果要在子线程里创建请求,必须要手动启动NSRunLoop,并且要在方法使用结束手动关闭NSRunLoop。
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]]; self .runloop = CFRunLoopGetCurrent ();CFRunLoopRun ();
在代理方法中使用完毕,停止runloop
- (void )connectionDidFinishLoading:(NSURLConnection *)connection { NSLog (@"--connectionDidFinishLoading--%@" ,[NSThread currentThread]); CFRunLoopStop (self .runloop); }
NSURLSession
这个是在iOS7之后推出的用于替代NSURLConnection的新类,推荐掌握这个 。
NSURLSession
主要由两部分组成,一个是Session实例对象,一个是任务。
使用步骤
创建task(dataTaskWithRequest
),启动task(resume
)
抽象类,使用其子类(NSURLSessionDataTask
、NSURLSessionDownloadTask
、NSURLSessionUploadTask
)
大小文件都一样,默认写入到tmp目录下面,下载完毕后要自己移动文件
NSURLSession
代理
初始化时设置代理<NSURLSessionDataDelegate>
实现过程
接收响应,指定响应方式:取消、下载、变为下载 didReceivedResponse
接收数据didReceivedData
接收完毕(成功和失败都会进入这个方法)didComplete
这个可以实现大文件下载
大文件断点下载
NSURLSession
的方法:suspend、resume、cancel
resumeData
保存暂停时程序数据状态,取消任务后要根据状态恢复下载
(不好 ,实现复杂)将下载的tmp文件保存到cachae,然后恢复现在时再从cache移动到临时文件
下载失败后要从NSError中获取失败时的恢复数据
何为断点下载
程序因意外事件终止,导致下载被停止,主要考虑用户突然关闭程序。
可以将下载的数据同步到沙盒中,并且记录下载大小,以及记录已下载的文件,每次下载之前都进行扫描一番。
如果下载一半就在请求头里指定要下载的范围
上传
NSURLSessionUploadTast
POST 请求设置注意methodBody
为上传的参数fromData
NSURLSessionConfiguration
统一配置(比如可以在这里设置是否允许设置程序使用蜂窝移动网络)
GET NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324" ];NSURLSession *session = [NSURLSession sharedSession];NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog (@"----%@" ,[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil ]); }]; [task resume];
POST NSURL *url = [NSURL URLWithString:@"http://123.123.123.123/login?username=123&pwd=4324" ];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 *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]; [[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__); } - (void )URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog (@"%s" ,__func__); } typedef NS_ENUM (NSInteger , NSURLSessionResponseDisposition ) { NSURLSessionResponseCancel = 0 , NSURLSessionResponseAllow = 1 , NSURLSessionResponseBecomeDownload = 2 , } 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 { [self .stream open]; 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 ; }
NSURLSession 上传文件
[[self .session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog (@"---%@" ,[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil ]); }] resume];
AFNetworking
GET\POST
AFHTTPRequestManager
AFHTTPSessionManager
- (void )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 { 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); }]; }
文件上传:appendPartWithFileData:
- (void )upload { AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; [mgr POST:@"http://123.123.123.123/upload" parameters:nil constructingBodyWithBlock:^(id <AFMultipartFormData> formData) { [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); }]; }
文件下载
下载文件需要返回一个保存路径,还需要手动启动resume
- (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) { 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 { AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager]; mgr.responseSerializer = [AFHTTPResponseSerializer 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]; [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { NSLog (@"网络状态改变:%zd" ,status); }]; [mgr startMonitoring]; }
手机联网状态: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 { 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加密
使用:主要是对用户的敏感信息进行加密
对输入信息生成唯一的128位散列值(32个字符)
根据输出值,不能得到原始的明文,即其过程不可逆
MD5改进
加盐(Salt):在明文的固定位置插入随机串,然后再进行MD5
先加密,后乱序:先对明文进行MD5,然后对加密得到的MD5串的字符进行乱序
等等,就是让信息更加复杂
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 ]); }];
2 实现代理方法 didReceiveChallenge
- (void )URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition , NSURLCredential *))completionHandler { if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust ]) { return ; } if (completionHandler) { completionHandler(NSURLSessionAuthChallengeUseCredential ,challenge.proposedCredential); } }
UIWebView
显示网页数据
代理方法<UIWebViewDelegate>
shouldStartLoadWithRequest
: 请求之前判断是否允许访问(过滤某些网址)
属性UIScrollView可以控制滚动范围
loadHTMLString
loadData:
可以加载网络资源和本地资源
scalesPageToFit
屏幕自适应
dataDetectorTypes
自动检测网页中出现的电话号码,网址等,添加下划线和链接。
- (void )webViewDidStartLoad:(UIWebView *)webView; - (void )webViewDidFinishLoad:(UIWebView *)webView; - (void )webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error; - (BOOL )webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType )navigationType;
- (BOOL )webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType )navigationType{ NSLog (@"%s" ,__func__); if ([request.URL.absoluteString containsString:@"life" ]) { return NO ; } return YES ; }
JS介绍 HTML5
html(内容) + CSS(样式) + JS(动态效果、事件交互)
常用JS函数
-alert(10); // 弹框
document.getElementById(‘test’); // 根据ID获得某个DOM元素
JS和OC通信
oc执行js
stringByEvaluatingJavaScriptFromString
JS 函数
function
JS执行OC
通过代理法方法 shouldStartLoadWithRequest
在js函数中调用 loaction.href = 'slq://sendMessage_?参数1&参数2';
传递参数的话,在方法后边写入一符号(_、@等)标识要传递参数,然后参数之间也要加入符号分割
OC执行JS
是用OC执行那个JS脚本
stringByEvaluatingJavaScriptFromString
[webView stringByEvaluatingJavaScriptFromString:@"alert(100)" ]; NSLog (@"%@" ,[webView stringByEvaluatingJavaScriptFromString:@"login();" ]); self .title = [webView stringByEvaluatingJavaScriptFromString:@"document.title;" ];
JS执行OC
- (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]) { NSString *method = [url substringFromIndex:pre.length]; [self performSelector:NSSelectorFromString (method) withObject:nil ]; return NO ; } return YES ; }
2个参数
使用’_’代替’:’,’?’区分参数和函数名,’&’区分参数
- (BOOL )webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType )navigationType { NSString *url = request.URL.absoluteString; NSString *pre = @"slq://" ; if ([url hasPrefix:pre]) { NSString *method = [url substringFromIndex:pre.length]; NSArray *arr = [method componentsSeparatedByString:@"?" ]; NSString *methodName = [[arr firstObject] stringByReplacingOccurrencesOfString:@"_" withString:@":" ]; 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]; return NO ; } return YES ; }
3个参数
如果有3个以上参数,只能使用方法签名的方式来确定传递参数
- (id )performSelector:(SEL)selector withObjects:(NSArray *)params { NSMethodSignature *sig = [[self class ] instanceMethodSignatureForSelector:selector]; if (sig == nil ) { NSLog (@"方法没找到" ); } NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sig]; invo.target = self ; invo.selector = selector; NSInteger paramNum = sig.numberOfArguments - 2 ; 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]; [[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 ignored "-Warc-performSelector-leaks"
异常处理
如果方法名错误,抛出异常 @throw
捕获异常 @try @catch @finally