美文网首页
多线程网络05

多线程网络05

作者: 努力爬行中的蜗牛 | 来源:发表于2019-12-15 13:55 被阅读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 相关框架

    • Mantal 需要继承自MIModel
    • JSONModel 需要继承自JSONModel
    • MJExtension 不需要继承,无代码侵入性

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

    • 侵入性
    • 易用性,是否容易上手
    • 扩展性,很容易给这个框架增加新的内容

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

    3 XML简单介绍

    3.1 XML语法 - 元素(Element)

    • 一个元素包括了开始标签和结束标签
    • 拥有内容的元素:<video>小黄人</video>
    • 没有内容的元素:<video></video>
    • 没有内容的元素简写:<video/>
    • 一个元素可以嵌套若干个子元素(不能出现交叉嵌套)
    • 规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素

    3.2 XML语法 - 元素的注意

    • 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解析

    • 想要从XML中提取有用的信息,必须得学会解析XML
      1)提取 name元素里面的内容
      <name>小黄人 第01部</name>
      2)提取video元素中namelength属性的值
      <video name="小黄人 第01部" length="30" />
    • XML的解析方式有2种
      1)DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
      2)SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

    3.5 iOS中的XML解析

    • 在iOS中,解析XML的手段很多
      1)苹果原生:NSXMLParser:SAX方式解析,使用简单
      2)第三方框架
      libxml2:纯c语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
      GDataXML:DOM方式解析,由Google开发,基于libxml2
    • XML解析方式的选择建议
      1)大文件:NSXMLParser、libxml2
      2)小文件:GDataXML、NSXMLParser、libxml2
    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配置

    • GDataXML基于libxml2库,得做以下配置
      导入libxml2
    • 设置libxml2的头文件搜索路径(为了能找到libxml2库的所有头文件)
      在Head Search Path中加入/usr/include/libxml2
    • 设置链接参数(自动链接libxml2库)
      在Other Linker Flags中加入-lmxl2
    • mrc文件编译方式-fno-objc-arc
    - (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]);
        }];
    }
    

    相关文章

      网友评论

          本文标题:多线程网络05

          本文链接:https://www.haomeiwen.com/subject/tzbcnctx.html