多线程网络05

2019-12-15  本文已影响0人  努力爬行中的蜗牛
1 JSON解析代码

1.1 JSON -> OC

- (void)jsonWithObj {
    //NSString *str = @"{\"error\":\"用户名不存在\"}"; //字典-NSJSONReadingMutableContainers
    //NSString *str = @"[\"error\",\"用户名不存在\"]"; //数组-NSJSONReadingMutableContainers
    //NSString *str = @"\"json string\""; //字符串-NSJSONReadingAllowFragments
    //NSString *str = @"false"; //数字 NSJSONReadingAllowFragments
     /*
     NSJSONReadingMutableContainers = (1UL << 0), 可变字典和数组
     NSJSONReadingMutableLeaves = (1UL << 1), 内部所有字符串都是可变的 ios7之后有问题,一般不用
     NSJSONReadingFragmentsAllowed = (1UL << 2), 既不是数组也不是字典,则必须使用该枚举值
     */
    NSString *str = @"null";
    id obj = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"%@---%@",[obj class],obj);
}

1.2 OC -> JSON

- (void)objToJson {
    NSDictionary *dict = @{
        @"name":@"xiaoming",
        @"age":@"2"
    };
    NSArray *arr = @[@"name",@"age"];
    NSString *str = @"hello world";
    // 并不是所有的对象都可以转换为JSON
    /*
     - 最外层必须是 NSArray or NSDictionary
     - 所有的元素是 NSString, NSNumber, NSArray, NSDictionary, or NSNull
     - 字典中所有的key必须是 NSStrings
     - NSNumbers 不能无穷大
     */
    BOOL isValid = [NSJSONSerialization isValidJSONObject:str];
    NSLog(@"%d",isValid);
    if (!isValid) {
        return;
    }
    /*
     参数1:要转换的OC对象
     参数2:选项NSJSONWritingPrettyPrinted 美化 排版
     */
    NSData *data = [NSJSONSerialization dataWithJSONObject:str options:NSJSONWritingPrettyPrinted error:nil];
    NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
2 MJExtension

2.1 相关框架

2.2 设计和选择框架时需要注意的问题

2.3 MJExtension是一套字典和模型之间互相转换的超级轻量框架

3 XML简单介绍

3.1 XML语法 - 元素(Element)

3.2 XML语法 - 元素的注意

// 第一个
<video>小黄人<video/>
// 第二个
<video>
        小黄人
<video/>

3.3 XML语法 - 属性(Attribute)

<video name="小黄人 第01部" length="30" />

video元素拥有 namelength两个属性
属性值必须用双引号"" 或者 单引号 '' 扩住

<video>
      <name>小黄人 第01部</name>
      <length>30</length>
</video>

3.4 XML解析

3.5 iOS中的XML解析

4 NSXMLParser解析XML:SAX
- (void)xml {
    NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Provinces.xml" ofType:nil]];
    //1 创建解析器
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    //2 设置代理
    parser.delegate = self;
    //3 解析文件
    [parser parse]; // 阻塞
}

#pragma mark - NSXMLParserDelegate
//1 开始解析xml文档
- (void)parserDidStartDocument:(NSXMLParser *)parser {
    NSLog(@"%s",__func__);
}

//2 开始解析xml某个元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
    if ([elementName isEqualToString:@"Provinces"]) {
        return;
    }
    NSLog(@"%@---%@",elementName,attributeDict);
}

//3 xml某个元素解析完毕
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    NSLog(@"%@元素解析完毕",elementName);
}

//4 xml文档解析完毕
- (void)parserDidEndDocument:(NSXMLParser *)parser {
    NSLog(@"%s",__func__);
}
5 GDataXML解析XML:DOM

5.1 GDataXML配置

- (void)xml {
    NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Provinces.xml" ofType:nil]];
    //1 加载xml文档
    GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:kNilOptions error:nil];
    //2 拿到根元素,得到元素内部所有名称为video的子孙元素
    NSArray *elements = [doc.rootElement elementsForName:@"Province"];
    //3 遍历
    for (GDataXMLElement *element in elements) {
        ProviceModel *model = [[ProviceModel alloc] init];
        model.provinceName = [element attributeForName:@"ProvinceName"].stringValue;
        [self.dataArray addObject:model];
    }
    NSLog(@"%zd",self.dataArray.count);
}

- (NSMutableArray *)dataArray {
    if (!_dataArray) {
        _dataArray = [NSMutableArray array];
    }
    return _dataArray;
}
6 多值参数和中文输出

6.1 多值参数
htpp://120.25.227.189:3244/weather?place=Sichuan&place=Beijing"
6.2 中文输出

#import <Foundation/Foundation.h>

@implementation NSDictionary (Log)

//重写系统的方法控制输出
-(NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
//    return @"你大爷是你大姐";
    NSMutableString *string = [NSMutableString string];
    
    //{}
    [string appendString:@"{"];
    
    //拼接key--value
    [self enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        [string appendFormat:@"%@:",key];
        [string appendFormat:@"%@,",obj];
        
    }];
    [string appendString:@"}"];
    
    //删除逗号
    //从后往前搜索 得到的是搜索到的第一个符号的位置
    NSRange range = [string rangeOfString:@"," options:NSBackwardsSearch];
    if (range.location != NSNotFound) {
        [string deleteCharactersInRange:range];
    }
    
    return string;
}

@end

@implementation NSArray (Log)

//重写系统的方法控制输出
-(NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
{
    //    return @"你大爷是你大姐";
    NSMutableString *string = [NSMutableString string];
    
    //{}
    [string appendString:@"["];
    
    //拼接obj
    [self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [string appendFormat:@"%@,\n",obj];
    }];

    [string appendString:@"]"];
    
    //删除逗号
    //从后往前搜索 得到的是搜索到的第一个符号的位置
    NSRange range = [string rangeOfString:@"," options:NSBackwardsSearch];
    if (range.location != NSNotFound) {
        [string deleteCharactersInRange:range];
    }

    return string;
}
7 NSURLConnection实现大文件下载

下载文件的时候,如果一次性下载下来,保存到内存,会导致内存飙升。
应该使用代理,将文件保存到本地。

-#import "ViewController.h"

@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progress;
@property (assign, nonatomic) NSInteger currentSize;

@property (assign, nonatomic) NSInteger totalSize;

@property (strong, nonatomic) NSURLConnection *connection;
@property (strong, nonatomic) NSFileHandle *handle;
@property (strong, nonatomic) NSString *fullPath;
@end

@implementation ViewController

- (IBAction)beginToDownLoad:(id)sender {
    [self download];
}

- (IBAction)stopToDownload:(id)sender {
    // 取消下载
    [self.connection cancel];
    NSLog(@"+++++++cancle");
}

//异步请求:代理方式
- (void)download {
    //1 url地址
    NSURL *url = [NSURL URLWithString:@"http://www.hitow.net/data/attachment/album/201612/10/205628nppuzll3137siny2.jpg"];
    //2 请求请求对象
    // 请求头不需要设置(默认请求头)
    NSMutableURLRequest *requet = [NSMutableURLRequest requestWithURL:url];
    // 设置请求头:告诉服务器请求一部分数据range
    /*
     bytes=0-100 请求前100个字节
     bytes=-100 请求最后100个字节
     bytes=100- 请求100之后的所有字节
     */
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
    [requet setValue:range forHTTPHeaderField:@"Range"];
    //3 发送异步请求
    self.connection = [[NSURLConnection alloc] initWithRequest:requet delegate:self];
}

#pragma mark - NSURLConnectionDataDelegate
// 1 客户端收到服务端响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"%s",__func__);
    //expectedContentLength:当前请求的数据大小,但不一定是整个下载文件的大小
    self.totalSize = response.expectedContentLength + self.currentSize;
    
    //获取文件下载路径
    NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    //使用服务端返回的建议文件名字
    NSString *fileName = response.suggestedFilename;
    //文件全路径
    self.fullPath = [filePath stringByAppendingPathComponent:fileName];
    
    //创建本地空文件
    [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
    //创建文件句柄
    self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
}
//2 客户端接收到服务端数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    //移动文件句柄到文件的末尾
    [self.handle seekToEndOfFile];
    //写入数据
    [self.handle writeData:data];
    
    // 获取当前下载文件的进度
    self.currentSize += data.length;
    CGFloat percent = (self.currentSize * 1.0)/self.totalSize;
    self.progress.progress = percent;
    NSLog(@"%f",percent);
}
//3 客户端数据请求失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%s",__func__);
}
//4 客户度数据请求完毕
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //关闭文件句柄
    [self.handle closeFile];
    self.handle = nil;
    NSLog(@"file download over");
}
8 输出流

输出流的方式和文件句柄类似,都是将从服务端获取的数据保存到指定的本地沙盒路径下。

#import "ViewController.h"

@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progress;
@property (assign, nonatomic) NSInteger currentSize;

@property (assign, nonatomic) NSInteger totalSize;

@property (strong, nonatomic) NSURLConnection *connection;
// 文件句柄
@property (strong, nonatomic) NSFileHandle *handle;
// 输出流
@property (strong, nonatomic) NSOutputStream *stream;
// 文件路径
@property (strong, nonatomic) NSString *fullPath;
@end

@implementation ViewController

- (IBAction)beginToDownLoad:(id)sender {
    [self download];
}

- (IBAction)stopToDownload:(id)sender {
    // 取消下载
    [self.connection cancel];
    NSLog(@"+++++++cancle");
}

//异步请求:代理方式
- (void)download {
    //1 url地址
    NSURL *url = [NSURL URLWithString:@"http://www.hitow.net/data/attachment/album/201612/10/205628nppuzll3137siny2.jpg"];
    //2 请求请求对象
    // 请求头不需要设置(默认请求头)
    NSMutableURLRequest *requet = [NSMutableURLRequest requestWithURL:url];
    // 设置请求头:告诉服务器请求一部分数据range
    /*
     bytes=0-100 请求前100个字节
     bytes=-100 请求最后100个字节
     bytes=100- 请求100之后的所有字节
     */
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
    [requet setValue:range forHTTPHeaderField:@"Range"];
    //3 发送异步请求
    self.connection = [[NSURLConnection alloc] initWithRequest:requet delegate:self];
}

#pragma mark - NSURLConnectionDataDelegate
// 1 客户端收到服务端响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"%s",__func__);
    //expectedContentLength:当前请求的数据大小,但不一定是整个下载文件的大小
    self.totalSize = response.expectedContentLength + self.currentSize;
    
    //获取文件下载路径
    NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    //使用服务端返回的建议文件名字
    NSString *fileName = response.suggestedFilename;
    //文件全路径
    self.fullPath = [filePath stringByAppendingPathComponent:fileName];
    
    //创建输出流
    /*
     参数1:文件路径
     参数2:是否追加
     特殊:如果本地没有该文件,会自动创建一个空的文件
     */
    self.stream = [NSOutputStream outputStreamToFileAtPath:self.fullPath append:YES];
    // 打开输出流
    [self.stream open];
}
//2 客户端接收到服务端数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    //保存数据到指定的路径
    [self.stream write:data.bytes maxLength:data.length];
    
    // 获取当前下载文件的进度
    self.currentSize += data.length;
    CGFloat percent = (self.currentSize * 1.0)/self.totalSize;
    self.progress.progress = percent;
    NSLog(@"%f",percent);
}
//3 客户端数据请求失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%s",__func__);
}
//4 客户度数据请求完毕
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //关闭输出流
    [self.stream close];
    self.stream = nil;
    
    NSLog(@"file download over");
}
9 NSURLConnection实现文件上传
//文件上传步骤
/*
 1.设置请求头 
 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx
 2.按照固定的格式拼接请求体的数据
 
 ------WebKitFormBoundaryjv0UfA04ED44AhWx
 Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
 Content-Type: image/png
 
 
 ------WebKitFormBoundaryjv0UfA04ED44AhWx
 Content-Disposition: form-data; name="username"
 
 123456
 ------WebKitFormBoundaryjv0UfA04ED44AhWx--
 
 */
//拼接请求体的数据格式
/*
 拼接请求体
 分隔符:----WebKitFormBoundaryjv0UfA04ED44AhWx
 1)文件参数
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
     Content-Type: image/png(MIMEType:大类型/小类型)
     空行
     文件参数
 2)非文件参数
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     123456
 3)结尾标识
    --分隔符--
 */
#import "ViewController.h"

#define Kboundary @"----WebKitFormBoundaryjv0UfA04ED44AhWx"
#define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self upload];
}

-(void)upload
{
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    
    //2.创建可变的请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //3.设置请求方法
    request.HTTPMethod = @"POST";
    
    //4.设置请求头信息
    //Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
    
    //5.拼接请求体数据
    NSMutableData *fileData = [NSMutableData data];
    //5.1 文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
     Content-Type: image/png(MIMEType:大类型/小类型)
     空行
     文件参数
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //name:file 服务器规定的参数
    //filename:Snip20160225_341.png 文件保存到服务器上面的名称
    //Content-Type:文件的类型
    [fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"Snip20160225_341.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    
    UIImage *image = [UIImage imageNamed:@"Snip20160225_341"];
    //UIImage --->NSData
    NSData *imageData = UIImagePNGRepresentation(image);
    [fileData appendData:imageData];
    [fileData appendData:KNewLine];
    
    //5.2 非文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     123456
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"123456" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //5.3 结尾标识
    /*
     --分隔符--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    //6.设置请求体
    request.HTTPBody = fileData;
    
    //7.发送请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
       
        //8.解析数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
}
上一篇下一篇

猜你喜欢

热点阅读