網(wǎng)絡(luò)02

JSON數(shù)據(jù)解析:

  • JSON的簡(jiǎn)單介紹:
    • 什么是JSON
    • JSON以一種輕量級(jí)的數(shù)據(jù)格式,一般用來(lái)數(shù)據(jù)交互
    • 服務(wù)器返回給客戶端的數(shù)據(jù)一般都是JSON或者XML格式(問(wèn)價(jià)下載除外)
    • JSON相關(guān)說(shuō)明
    • JSON格式很想oc中的字典
    • 標(biāo)準(zhǔn)JSON格式中的key必須是雙引號(hào)
    • 解析JSON的方案
    • 第三方框架
    • 蘋果原生:NSJSONSerialization
  • JSON解析相關(guān)代碼
    • JSON數(shù)據(jù)->OC(反序列化)
      //把json數(shù)據(jù)轉(zhuǎn)換為OC對(duì)象
         -(void)jsonToOC
         {
             //1. 確定url路徑
             NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=33&pwd=33&type=JSON"];
    
             //2.創(chuàng)建一個(gè)請(qǐng)求對(duì)象
             NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
             //3.使用NSURLSession發(fā)送一個(gè)異步請(qǐng)求
             [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    
                 //4.當(dāng)接收到服務(wù)器響應(yīng)的數(shù)據(jù)后,解析數(shù)據(jù)(JSON--->OC)
    
                 /*
                  第一個(gè)參數(shù):要解析的JSON數(shù)據(jù),是NSData類型也就是二進(jìn)制數(shù)據(jù)
                  第二個(gè)參數(shù): 解析JSON的可選配置參數(shù)
                  NSJSONReadingMutableContainers 解析出來(lái)的字典和數(shù)組是可變的
                  NSJSONReadingMutableLeaves 解析出來(lái)的對(duì)象中的字符串是可變的  iOS7以后有問(wèn)題
                  NSJSONReadingAllowFragments 被解析的JSON數(shù)據(jù)如果既不是字典也不是數(shù)組, 那么就必須使用這個(gè)
                  */
                 NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
                 NSLog(@"%@",dict);
    
             }];
         }
    
    • OC對(duì)象->JSON對(duì)象
      //1.要轉(zhuǎn)換成JSON數(shù)據(jù)的OC對(duì)象*這里是一個(gè)字典
            NSDictionary *dictM = @{
                                    @"name":@"wendingding",
                                    @"age":@100,
                                    @"height":@1.72
                                    };
            //2.OC->JSON
            /*
             注意:可以通過(guò)+ (BOOL)isValidJSONObject:(id)obj;方法判斷當(dāng)前OC對(duì)象能否轉(zhuǎn)換為JSON數(shù)據(jù)
             具體限制:
                 1.obj 是NSArray 或 NSDictionay 以及他們派生出來(lái)的子類
                 2.obj 包含的所有對(duì)象是NSString,NSNumber,NSArray,NSDictionary 或NSNull
                 3.字典中所有的key必須是NSString類型的
                 4.NSNumber的對(duì)象不能是NaN或無(wú)窮大
             */
            /*
             第一個(gè)參數(shù):要轉(zhuǎn)換成JSON數(shù)據(jù)的OC對(duì)象,這里為一個(gè)字典
             第二個(gè)參數(shù):NSJSONWritingPrettyPrinted對(duì)轉(zhuǎn)換之后的JSON對(duì)象進(jìn)行排版,無(wú)意義
             */
            NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
    
            //3.打印查看Data是否有值
            /*
             第一個(gè)參數(shù):要轉(zhuǎn)換為STring的二進(jìn)制數(shù)據(jù)
             第二個(gè)參數(shù):編碼方式,通常采用NSUTF8StringEncoding
             */
            NSString *strM = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@",strM);
    
  • OC對(duì)象與JSON對(duì)象之間的一一對(duì)應(yīng)關(guān)系
      //OC對(duì)象和JSON數(shù)據(jù)之間的一一對(duì)應(yīng)關(guān)系
         -(void)oCWithJSON
         {
             //JSON的各種數(shù)據(jù)格式
             //NSString *test = @"\"wendingding\"";
             //NSString *test = @"true";
             NSString *test = @"{\"name\":\"wendingding\"}";
    
             //把JSON數(shù)據(jù)->OC對(duì)象,以便查看他們之間的一一對(duì)應(yīng)關(guān)系
             //注意點(diǎn):如何被解析的JSON數(shù)據(jù)如果既不是字典也不是數(shù)組(比如是NSString), 那么就必須使用這NSJSONReadingAllowFragments
             id obj = [NSJSONSerialization JSONObjectWithData:[test dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
    
             NSLog(@"%@", [obj class]);
             /* JSON數(shù)據(jù)格式和OC對(duì)象的一一對(duì)應(yīng)關(guān)系
                  {} -> 字典
                  [] -> 數(shù)組
                  "" -> 字符串
                  10/10.1 -> NSNumber
                  true/false -> NSNumber
                  null -> NSNull
              */
         }
         }
    
  • 如何查看復(fù)雜的JSON數(shù)據(jù)
    ```objc
     [dictM writeToFile:@"/Users/文頂頂/Desktop/videos.plist" atomically:YES];
     ```
    
  • 視頻的簡(jiǎn)單播放
      //0.需要導(dǎo)入系統(tǒng)框架
     #import <MediaPlayer/MediaPlayer.h>
    
     //1.拿到該cell對(duì)應(yīng)的數(shù)據(jù)字典
     XMGVideo *video = self.videos[indexPath.row];
    
     NSString *videoStr = [@"http://120.25.226.186:32812" stringByAppendingPathComponent:video.url];
    
     //2.創(chuàng)建一個(gè)視頻播放器
     MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:videoStr]];
     //3.present播放控制器
    
     [self presentViewController:vc animated:YES completion:nil];
    
  • MJExtension
  • 簡(jiǎn)單使用
```objc
  //1.把字典數(shù)組轉(zhuǎn)換為模型數(shù)組
        //使用MJExtension框架進(jìn)行字典轉(zhuǎn)模型
            self.videos = [XMGVideo mj_objectArrayWithKeyValuesArray:videoArray];

    //2.重命名模型屬性的名稱
    //第一種重命名屬性名稱的方法,有一定的代碼侵入性
    //設(shè)置字典中的id被模型中的ID替換
    +(NSDictionary *)mj_replacedKeyFromPropertyName
    {
        return @{
                 @"ID":@"id"
                 };
    }

    //第二種重命名屬性名稱的方法,代碼侵入性為零
        [XMGVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
            return @{
                     @"ID":@"id"
                     };
        }];

    //3.MJExtension框架內(nèi)部實(shí)現(xiàn)原理-運(yùn)行時(shí)
```

XML解析

  • XML解析
  • 使用XMLParser
  //1.發(fā)送請(qǐng)求
 [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

     //2.解析數(shù)據(jù)
     //2.1 創(chuàng)建XML解析器
     NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];

     //2.2 設(shè)置代理
     parser.delegate = self;

     //2.3 開(kāi)始解析,該方法本身是阻塞的
     [parser parse];

     //4.刷新tableView
     dispatch_async(dispatch_get_main_queue(), ^{
          [self.tableView reloadData];
     });
 }] resume];

 //1.開(kāi)始解析XML文檔
     -(void)parserDidStartDocument:(nonnull NSXMLParser *)parser

     //2.開(kāi)始解析XML中某個(gè)元素的時(shí)候調(diào)用,比如<video>
     -(void)parser:(nonnull NSXMLParser *)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary<NSString *,NSString *> *)attributeDict
     {
         if ([elementName isEqualToString:@"videos"]) {
             return;
         }
         //字典轉(zhuǎn)模型
         XMGVideo *video = [XMGVideo objectWithKeyValues:attributeDict];
         [self.videos addObject:video];
     }

     //3.當(dāng)某個(gè)元素解析完成之后調(diào)用,比如</video>
     -(void)parser:(nonnull NSXMLParser *)parser didEndElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName

     //4.XML文檔解析結(jié)束
     -(void)parserDidEndDocument:(nonnull NSXMLParser *)parser
  • MJExtension使用小技巧
```objc
//0.告訴框架新值和舊值的對(duì)應(yīng)關(guān)系
[XMGVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
    return @{
             @"ID":@"id",
             };

}];
```
  • NSURLSessionDownloadTask大文件下載
  • NSURLSessionDownloadTask實(shí)現(xiàn)大文件下載-Block
  • 使用URLSession和URLSessionDownload可以很方便的實(shí)現(xiàn)文件下載
  ```objc
    1)使用NSURLSession和NSURLSessionDownload可以很方便的實(shí)現(xiàn)文件下載操作
 /*
     第一個(gè)參數(shù):要下載文件的url路徑
     第二個(gè)參數(shù):當(dāng)接收完服務(wù)器返回的數(shù)據(jù)之后調(diào)用該block
     location:下載的文件的保存地址(默認(rèn)是存儲(chǔ)在沙盒中tmp文件夾下面,隨時(shí)會(huì)被刪除)
     response:服務(wù)器響應(yīng)信息,響應(yīng)頭
     error:該請(qǐng)求的錯(cuò)誤信息
     */
    //說(shuō)明:downloadTaskWithURL方法已經(jīng)實(shí)現(xiàn)了在下載文件數(shù)據(jù)的過(guò)程中邊下載文件數(shù)據(jù),邊寫入到沙盒文件的操作
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * __nullable location, NSURLResponse * __nullable response, NSError * __nullable error)
  ```
-  downloadTaskWithURL內(nèi)部已經(jīng)實(shí)現(xiàn)了邊下載邊寫入操作,所以開(kāi)發(fā)人員不必?fù)?dān)心內(nèi)存問(wèn)題
- 文件下載后默認(rèn)保存到tmp目錄,需要手動(dòng)剪切到指定的沙盒目錄
- 缺點(diǎn):無(wú)法監(jiān)聽(tīng)下載進(jìn)度
  • 使用NSURLSessionDownloadTask實(shí)現(xiàn)大文件下載-代理
  • 創(chuàng)建NSURLSession并設(shè)置代理,通過(guò)NSURLSessionDownloadTask并以代理的方式實(shí)現(xiàn)大文件的下載
      //1.創(chuàng)建NSULRSession,設(shè)置代理
      self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
      //2.創(chuàng)建task
      NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
      self.downloadTask = [self.session downloadTaskWithURL:url];
    
      //3.執(zhí)行task
      [self.downloadTask resume];
    
  • 常用代理方法說(shuō)明
  ```objc
      /*
     1.當(dāng)接收到下載數(shù)據(jù)的時(shí)候調(diào)用,可以在該方法中監(jiān)聽(tīng)文件下載的進(jìn)度
     該方法會(huì)被調(diào)用多次
     totalBytesWritten:已經(jīng)寫入到文件中的數(shù)據(jù)大小
     totalBytesExpectedToWrite:目前文件的總大小
     bytesWritten:本次下載的文件數(shù)據(jù)大小
     */
    -(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
    /*
     2.恢復(fù)下載的時(shí)候調(diào)用該方法
     fileOffset:恢復(fù)之后,要從文件的什么地方開(kāi)發(fā)下載
     expectedTotalBytes:該文件數(shù)據(jù)的總大小
     */
    -(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
    /*
     3.下載完成之后調(diào)用該方法
     */
    -(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
    /*
     4.請(qǐng)求完成之后調(diào)用
     如果請(qǐng)求失敗,那么error有值
     */
    -(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
  ```
-  實(shí)現(xiàn)斷點(diǎn)下載相關(guān)代碼:
  ```objc
    //如果任務(wù),取消了那么以后就不能恢復(fù)了
    //    [self.downloadTask cancel];

    //如果采取這種方式來(lái)取消任務(wù),那么該方法會(huì)通過(guò)resumeData保存當(dāng)前文件的下載信息
    //只要有了這份信息,以后就可以通過(guò)這些信息來(lái)恢復(fù)下載
    [self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
        self.resumeData = resumeData;
    }];

    -----------
    //繼續(xù)下載
    //首先通過(guò)之前保存的resumeData信息,創(chuàng)建一個(gè)下載任務(wù)
    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];

     [self.downloadTask resume];
  ```
-  計(jì)算當(dāng)前下載進(jìn)度
  ```objc
     //獲取文件下載進(jìn)度
    self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;
  ```
-  局限性:
  ```objc
    01 如果用戶點(diǎn)擊暫停之后退出程序,那么需要把恢復(fù)下載的數(shù)據(jù)寫一份到沙盒,代碼復(fù)雜度更
    02 如果用戶在下載中途未保存恢復(fù)下載數(shù)據(jù)即退出程序,則不具備可操作性
  ```
  • NSURLSessionDataTask實(shí)現(xiàn)大文件下載:
    • 關(guān)于NSOutputStream的使用
      //1. 創(chuàng)建一個(gè)輸入流,數(shù)據(jù)追加到文件的屁股上
     //把數(shù)據(jù)寫入到指定的文件地址,如果當(dāng)前文件不存在,則會(huì)自動(dòng)創(chuàng)建
    NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];
    
      //2. 打開(kāi)流
    [stream open];
    
      //3. 寫入流數(shù)據(jù)
    [stream write:data.bytes maxLength:data.length];
    
     //4.當(dāng)不需要的時(shí)候應(yīng)該關(guān)閉流
    [stream close];
    
    • 關(guān)于網(wǎng)絡(luò)請(qǐng)求頭的設(shè)置(可以設(shè)置指定下載某一部分文件)
      //1. 設(shè)置請(qǐng)求對(duì)象
      //1.1 創(chuàng)建請(qǐng)求路徑
      NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    
       //1.2 創(chuàng)建可變請(qǐng)求對(duì)象
      NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
       //1.3 拿到當(dāng)前文件的殘留數(shù)據(jù)大小
      self.currentContentLength = [self FileSize];
    
       //1.4 告訴服務(wù)器從哪個(gè)地方開(kāi)始下載文件數(shù)據(jù)
       NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
      NSLog(@"%@",range);
    
      //1.5 設(shè)置請(qǐng)求頭
      [request setValue:range forHTTPHeaderField:@"Range"];
    
    • NSURLSession對(duì)象的釋放
            -(void)dealloc
          {
             //在最后的時(shí)候應(yīng)該把session釋放,以免造成內(nèi)存泄露
            //    NSURLSession設(shè)置過(guò)代理后,需要在最后(比如控制器銷毀的時(shí)候)調(diào)用session的invalidateAndCancel或者resetWithCompletionHandler,才不會(huì)有內(nèi)存泄露
            //    [self.session invalidateAndCancel];
           [self.session resetWithCompletionHandler:^{
      
            NSLog(@"釋放---");
           }];
          }
      

文件的壓縮與解壓縮

  • 說(shuō)明:
  • 使用ZipArchive來(lái)壓縮和解壓縮文件需要添加依賴庫(kù)(libz),使用需要包含SSZipArchive文件,如果使用cocoaPoads來(lái)安裝框架,那么會(huì)自動(dòng)的配置框架的使用環(huán)境
  • 相關(guān)代碼實(shí)現(xiàn):
      //壓縮文件的第一種方式
         /*
          第一個(gè)參數(shù):壓縮文件要保存的位置
          第二個(gè)參數(shù):要壓縮哪幾個(gè)文件
          */
         [SSZipArchive createZipFileAtPath:fullpath withFilesAtPaths:arrayM];
    
         //壓縮文件的第二種方式
         /*
          第一個(gè)參數(shù):文件壓縮到哪個(gè)地方
          第二個(gè)參數(shù):要壓縮文件的全路徑
          */
         [SSZipArchive createZipFileAtPath:fullpath withContentsOfDirectory:zipFile];
    
         //如何對(duì)壓縮文件進(jìn)行解壓
         /*
          第一個(gè)參數(shù):要解壓的文件
          第二個(gè)參數(shù):要解壓到什么地方
          */
         [SSZipArchive unzipFileAtPath:unZipFile toDestination:fullpath];
    

多值參數(shù)和中文輸出

  • 多值參數(shù)
       /*
      如果一個(gè)參數(shù)對(duì)應(yīng)著多個(gè)值,那么直接按照"參數(shù)=值&參數(shù)=值"的方式拼接
      */
     -(void)test
     {
         //1.確定URL
         NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/weather?place=Beijing&place=Guangzhou"];
         //2.創(chuàng)建請(qǐng)求對(duì)象
         NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
         //3.發(fā)送請(qǐng)求
         [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    
             //4.解析
             NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
         }];
     }
    
    
  • 如何解決字典或者數(shù)組輸出亂碼的問(wèn)題
  給字典和數(shù)組添加一個(gè)分類,重寫descriptionWithLocale方法,在該方法中拼接元素格式化輸出。
  -(nonnull NSString *)descriptionWithLocale:(nullable id)locale
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容