一 JSON
- 什么是JSON
- JSON是一种轻量级的数据格式,一般用于数据交互
- 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外)
- JSON和OC对象转换后对应数据类型
{} -> NSDictionary @{}
[] -> NSArray @[]
"jack" -> NSString @"jack"
10 -> NSNumber @10
10.5 -> NSNumber @10.5
true -> NSNumber @1
false -> NSNumber @0
null -> NSNull
- JSON解析方案
- 第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)
- 苹果原生(自带):NSJSONSerialization(性能最好)
- NSJSONSerialization的常见方法
// JSON数据 → OC对象
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
- NSJSONReadingOptions
- NSJSONReadingMutableContainers = (1UL << 0)
- 创建出来的数组和字典就是可变
- NSJSONReadingMutableLeaves = (1UL << 1)
- 数组或者字典里面的字符串是可变的, iOS7以后无效
- NSJSONReadingAllowFragments
- 允许解析出来的对象不是字典或者数组,比如直接是字符串或者NSNumber
- NSJSONReadingMutableContainers = (1UL << 0)
// OC对象 → JSON数据
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
- 格式化服务器返回的JSON数据
- 在线格式化:http://tool.oschina.net/codeformat/json
- 将服务器返回的字典或者数组写成plist文件
- 复杂JSON数据解析案例代码
@interface ViewController ()
@property (nonatomic, strong) NSArray *videos; /**< 视屏信息 */
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = 150;
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.videos = dict[@"videos"];
// 注意: 拿到数据之后一定要刷新表格
[self.tableView reloadData];
}];
}
#pragma mark - datasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.videos.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.创建cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
// 2.取出对应行的字典
NSDictionary *dict = self.videos[indexPath.row];
// 2.1设置数据
cell.textLabel.text = dict[@"name"];
cell.detailTextLabel.text = [NSString stringWithFormat:@"时长:%@", dict[@"length"]];
NSString *urlStr = [NSString stringWithFormat:@"http://120.25.226.186:32812/%@", dict[@"image"]];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:urlStr] placeholderImage:nil];
// 3.返回cell
return cell;
}
// 监听点击
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.取出选中行对应的字典
NSDictionary *dict = self.videos[indexPath.row];
// 2.根据字典中的URL属性拼接视屏的地址
NSString *urlStr = [NSString stringWithFormat:@"http://120.25.226.186:32812/%@", dict[@"url"]];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
// 3.播放视屏
MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
// 4.显示控制器
[self presentViewController:vc animated:YES completion:nil];
}
@end
二 字典转模型框架
- Mantle
- 所有模型都必须继承自MTModel
- JSONModel
- 所有模型都必须继承自JSONModel
- MJExtension
- 不需要强制继承任何其他类
设计框架需要考虑的问题
- 侵入性
- 侵入性大就意味着很难离开这个框架
- 易用性
- 比如少量代码实现N多功能
- 扩展性
- 很容易给这个框架增加新框架
利用苹果官方API播放视频
// 创建视频播放器
MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:urlStr]];
// 显示视频
[self presentViewController:vc animated:YES completion:nil];
三 XML
- 什么是XML
- 全称是Extensible Markup Language,译作“可扩展标记语言”
- 跟JSON一样,也是常用的一种用于交互的数据格式
- 一般也叫XML文档(XML Document)
XML语法
文档声明
- 声明XML文档的类型
元素(Element)
- 一个元素包括了开始标签和结束标签
属性(Attribute)
- 一个元素可以拥有多个属性
- XML的解析方式
- SAX
- 大小文件都可以
- NSXMLParser
- DOM
- 最好是小文件
- GDataXML
- SAX
四 XML-SAX解析 NSXMLParser
- 创建解析器来解析
// 创建XML解析器
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
// 设置代理
parser.delegate = self;
// 开始解析XML(parse方法是阻塞式的)
[parser parse];
- 代理对象要遵守NSXMLParserDelegate协议,实现代理方法
/**
* 解析到某个元素的结尾(比如解析</videos>)
*/
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
}
/**
* 解析到某个元素的开头(比如解析<videos>)
*/
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
}
/**
* 开始解析XML文档
*/
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
}
/**
* 解析完毕
*/
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
}
五 XML-DOM解析
- GDataXML基于libxml2库,得做以下配置:
- GDataXML是非ARC的,因此得设置编译参数
- 具体用法
// 加载整个文档
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
// 获得根节点
doc.rootElement;
// 获得其他节点
[element elementsForName:@"video"];
// 获得节点的属性
[element attributeForName:@"name"].stringValue;
六 小文件下载
- 方法一
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_15.png"];
NSData *data = [NSData dataWithContentsOfURL:url];
- 方法二
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_15.png"];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
}];
七 大文件下载
- 如果是大文件下载,建议使用NSURLSession或者第三方框架
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_15.mp4"];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
// 判断如果有数据, 就不需要重新创建
if (self.currentLength) return;
// 获取文件总大小
// self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
self.contentLength = response.expectedContentLength;
NSLog(@"%@", XMGFile);
// 创建一个空的文件
[[NSFileManager defaultManager] createFileAtPath:XMGFile contents:nil attributes:nil];
// 创建文件句柄
self.handle = [NSFileHandle fileHandleForWritingAtPath:XMGFile];
}
// 不将文件保存到内存中,一边下载一边写入磁盘中,防止内存暴增
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
// 指定数据的写入位置 -- 文件内容的最后面
[self.handle seekToEndOfFile];
// 写入数据
[self.handle writeData:data];
// 拼接总长度
self.currentLength += data.length;
self.progressView.progress = 1.0 * self.currentLength / self.contentLength;
NSLog(@"%f", self.progressView.progress);
}
// 下载完毕一定要关闭文件句柄
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 关闭handle
[self.handle closeFile];
self.handle = nil;
// 清空长度
self.currentLength = 0;
self.contentLength = 0;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
八 输出流
- 用NSOutputStream可以将网络请求的资源回来的数据保存到本地文件
- (NSOutputStream *)outputStream
{
if (!_outputStream) {
/*
第一个参数: 告诉系统数据流需要输出到哪个文件中
第二个参数: 如果传入YES, 代表每次都在上一次的后面追加
如果传入NO, 代表每次都从头开始
*/
_outputStream = [NSOutputStream outputStreamToFileAtPath:self.path append:YES];
// 注意: 如果想利用输出流写入数据, 一定要打开数据流
// 如果数据流打开的文件不存在, 那么会自动创建个新的
[_outputStream open];
}
return _outputStream;
}
// 接收到服务器的数据调用(会调用一次或多次)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 直接写入数据
/*
第一个参数: 需要写入的数据
第二个参数: 写入数据的大小
*/
[self.outputStream write:data.bytes maxLength:data.length];
// 计算进度
self.currentLength += data.length;
self.progressView.progress = 1.0 * self.currentLength / self.totalLength;
}
// 接收完毕时调用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 关闭输出流
[self.outputStream close];
self.outputStream = nil;
}
九 文件断点下载
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 拿到当前已经下载文件的大小
NSString *path = [@"minion_01.mp4" cacheDir];
NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *dict = [manager attributesOfItemAtPath:path error:nil];
//设置请求头
/*
表示头500个字节:bytes= 0-499
表示第二个500个字节:bytes= 500-999
表示最后500个字节:bytes= -500
表示500字节以后的范围:bytes= 500-
第一个和最后一个字节:bytes=0-0,-1
同时指定几个范围:bytes= 300~499,500-899
*/
// 注意:从文件中获取出来的大小一定要先转换为integerVa,否则是null
NSString *range = [NSString stringWithFormat:@"bytes:%zd-",[dict[NSFileSize] integerValue]];
[request setValue:range forHTTPHeaderField:@"Range"];
[NSURLConnection connectionWithRequest:request delegate:self];
十 文件压缩/解压缩
- ZipArchive
- 下载地址:https://github.com/ZipArchive/ZipArchive
- 需要引入libz.dylib框架
- 压缩
+ (BOOL)createZipFileAtPath:(NSString *)path
withFilesAtPaths:(NSArray *)paths;
+ (BOOL)createZipFileAtPath:(NSString *)path
withContentsOfDirectory:(NSString *)directoryPath;
- 解压缩
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
十一 文件上传
[request setValue:@"multipart/form-data; boundary=分割线" forHTTPHeaderField:@"Content-Type"];
设置请求体
- 文件参数
--分割线\r\n
Content-Disposition: form-data; name="参数名"; filename="文件名"\r\n
Content-Type: 文件的MIMEType\r\n
\r\n
文件数据
\r\n
- 非文件参数
--分割线\r\n
Content-Disposition: form-data; name="参数名"\r\n
\r\n
参数值
\r\n
- 结束标记
参数结束的标记
--分割线--\r\n
注意事项
- 请求体比请求头分割线前面
多两个--
- 结束标记比请求体后面
多两个--
十二 MIMEType
- 请求体比请求头分割线前面
利用NSURLConnection
- 万能类型 application/octet-
部分文件的MIMEType
- (NSString *)MIMEType:(NSURL *)url
{
// 1.创建一个请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2.发送请求(返回响应)
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
// 3.获得MIMEType
return response.MIMEType;
}
- C语言API(了解)
+ (NSString *)mimeTypeForFileAtPath:(NSString *)path
{
if (![[NSFileManager alloc] init] fileExistsAtPath:path]) {
return nil;
}
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!MIMEType) {
return @"application/octet-stream";
}
return NSMakeCollectable(MIMEType);
}