美文网首页iOS网络iOS网络请求
2.1 请求相关及其问题

2.1 请求相关及其问题

作者: SoftKnife | 来源:发表于2015-10-05 14:10 被阅读117次
    People Lack Willpower,Rather Than Strength!
    

    1.简单请求.url中的多值参数问题

    • 如下代码

      NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/weather?place=Beijing&place=Guangzhou&place=Shanghai"];
      
      • 这里虽然多个value的key相同,但是是也不可以写成如下形式:

        place=Beijing,Guangzhou,Shanghai
        

    2.服务器返回数据的打印问题

    • 已知通过NSString打印,查看data,是OK的,因为data转换为String时,完成了转码,不会出现中文显示问题,如下:

      NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);// ✅
      
      // 2015-09-12 23:51:32.594 06-多值参数与打印字典转码问题[6619:332762] {"weathers":[{"city":"Beijing","status":"晴转多云"},{"city":"Guangzhou","status":"晴转多云"},{"city":"Shanghai","status":"晴转多云"}]}
      
    • 然而,如果我们想打印NSDictionary ,如果字典中有中文,打印效果不佳 ❌

      NSLog(@"%@",dict);
      /*
      2015-09-12 23:51:32.595 06-多值参数与打印字典转码问题[6619:332762] {
          weathers =     (
                      {
                  city = Beijing;
                  status = "\U6674\U8f6c\U591a\U4e91";
              },
                      {
                  city = Guangzhou;
                  status = "\U6674\U8f6c\U591a\U4e91";
              },
                      {
                  city = Shanghai;
                  status = "\U6674\U8f6c\U591a\U4e91";
              }
          );
      }
      */
      
    • 如果我们想很好的显示中文,需要重写NSDictionary的descriptionWithLocale方法;

      • 同时,需要注意,NSArray打印中文也有问题,也需要重写;

        #import <Foundation/Foundation.h>
        @implementation NSDictionary (nslog)
        
        - (NSString *)descriptionWithLocale:(id)locale
        {
            // 创建一个可变字符串用于描述字典打印样式和内容
            NSMutableString *stringM = [NSMutableString string];
            // 开头
            [stringM appendString:@"{\n"];
        
            // 内容,遍历字典中键值对,将他们拼接到字符串中
            [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                [stringM appendString:[NSString stringWithFormat:@"\t%@ = %@,\n",key,obj]];
            }];
        
            // 末尾
            [stringM appendString:@"}\n"];
        
            if (self.allKeys.count) {
                // 删除字典-->字符串中最后一个逗号
                NSRange range = [stringM rangeOfString:@"," options:NSBackwardsSearch];
                [stringM deleteCharactersInRange:range];
            }
            return stringM;
        }
        @end
        
        @implementation NSArray (nslog)
        - (NSString *)descriptionWithLocale:(id)locale
        {
            // 创建一个可变字符串用于描述字典打印样式和内容
            NSMutableString *stringM = [NSMutableString string];
            // 开头
            [stringM appendString:@"(\n"];
        
            // 遍历数组中的元素,将他们拼接到字符串中
            [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                [stringM appendString:[NSString stringWithFormat:@"\t%@,",obj]];
            }];
            // 末尾
            [stringM appendString:@")\n"];
        
            // 删除最后一个逗号
            if (self.count) {
                NSRange range = [stringM rangeOfString:@"," options:NSBackwardsSearch];
                [stringM deleteCharactersInRange:range];
            }
            return stringM;
        }
        @end
        
        // 那么打印结果如下:
        /*
        2015-09-12 23:59:03.169 06-多值参数与打印字典转码问题[6674:337315] {
            weathers = (
            {
            status = 晴转多云,
            city = Beijing
        }
        ,   {
            status = 晴转多云,
            city = Guangzhou
        }
        ,   {
            status = 晴转多云,
            city = Shanghai
        }
        )
        
        }
        */
        

    3.请求还有哪些类型?

    3.1文件下载

    • 大小文件下载区别:

      • 1.小文件由于体积比较小,所以可以一次性全部加载到内存,然后再写入硬盘;

      • 2.而大文件则不然,由于体积较大如果一次性都加载到内存,再写入硬盘显然是不行的,所以需要下一点,往硬盘里存一些!

    3.1.1小文件下载

    // 小文件下载
    
    //1.直接使用url下载
    
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];
    
    //2.发请求
    // 1.url
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
    // 2.request
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 3.sendrequest
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        UIImage *image = [UIImage imageWithData:data];
        NSLog(@"%@",image);
    }];
    

    3.1.2大文件下载

    • 对于大文件下载,由于资源较大,我们需要使用代理方法,在代理方法中逐段接收下载data!同时,文件较大时,我们应该将文件逐段写入硬盘,而不是存入内存,这样可以减少内存压力!

    • 常见的文件操作方法

      • 文件句柄

            - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
        {
            // 1.使用http get方法发送请求
            NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
            // 2.创建request
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            // 3.NSURLConnection发送请求,由于资源较大,我们需要使用代理方法分块下载
            [NSURLConnection connectionWithRequest:request delegate:self];
        
        }
        
        #pragma mark - NSURLConnectionDataDelegate
        // 接收到服务器响应时调用
        - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
        {
            // 1.获得下载文件存储路径
            NSString *path = [response.suggestedFilename cacheDir];
            self.path = path;
            // 2.创建一个空文件
            NSFileManager *manager = [NSFileManager defaultManager];
            if ([manager createFileAtPath:self.path contents:nil attributes:nil]) {
                NSLog(@"创建成功");
            }
            // 3.懒加载文件句柄对象,设置句柄操作文件写入方式
            // 这样能保证,每次写入到文件中的数据是从紧挨着有数据的空区域开始的!❤️
            [self.handle seekToEndOfFile];
        
            // 记录服务器反馈文件总大小
            self.totalLength = response.expectedContentLength;
        
        }
        // 接收到服务器的数据时调用(可能调用一次或者多次)
        - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
        {
            // 4.使用文件句柄写入data到空文件中
            [self.handle writeData:data];
        
            // 实时计算下载进度
            self.currentLength += data.length;
            self.progressView.progress = 1.0 * self.currentLength / self.totalLength;
        }
        // 结束加载时,调用
        - (void)connectionDidFinishLoading:(NSURLConnection *)connection
        {
            // 5.结束时,记得要关闭文件和句柄
            [self.handle closeFile];
            self.handle = nil;
        }
        
        // 懒加载句柄
        - (NSFileHandle *)handle
        {
            if (!_handle) {
                _handle = [NSFileHandle fileHandleForWritingAtPath:self.path];
            }
            return _handle;
        }
        
      • 输出流

       -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
       {
           // 1.使用http get方法发送请求
           NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
           // 2.创建request
           NSURLRequest *request = [NSURLRequest requestWithURL:url];
           // 3.NSURLConnection发送请求,由于资源较大,我们需要使用代理方法分块下载
           [NSURLConnection connectionWithRequest:request delegate:self];
       }
       /*==============================代理方法==================================*/
       #pragma mark - NSURLConnectionDataDelegate
       // 接收到服务器响应时调用
       (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
       {
         // 1.获得下载文件存储路径
         NSString *path = [response.suggestedFilename cacheDir];
         self.path = path;
       
         // 记录服务器反馈文件总大小
         self.totalLength = response.expectedContentLength;
       }
       
       // 接收到服务器的数据时调用(可能调用一次或者多次)
       -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
       
       {
         // 2.使用输出流写入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
       {
         // 3.结束时,记得要关闭文件和输出流
         [self.outputStream close];
         self.outputStream = nil;
       }
       /*==============================代理方法==================================*/
       // 懒加载输出流
       - (NSOutputStream *)outputStream
       {
       
           if (!_outputStream) {
               /*
                参数一:表示要输出到哪里;
                参数二:表示每次输出都是拼接到新下数据后面
                */
               _outputStream = [NSOutputStream outputStreamToFileAtPath:self.path append:YES];
       
               // 注意:如果想利用输出流写入数据,一定要打开输出流!!⚠️
               //如果数据流打开的文件不存在, 那么会自动创建个新的
               [_outputStream open];
           }
           return _outputStream;
       }
      
      • 对比二者,可见输出流略胜一筹!

    3.1.3大文件断点下载

    • 关键: 如果想进行断点下载,我们需要在请求头中设置文件下载的range,告诉服务器,我们需要从文件的哪个位置开始下载❤️

      - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
      {
          // 1.使用http get方法发送请求
          NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
          // 2.创建request
          NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
      
      #warning 设置请求头,以便断点下载🆘
          // 设置path
          self.path = [@"minion_01.mp4" cacheDir];
      
          // 设置每次下载时currentLength初始值
          self.currentLength = [self fileSize:self.path];
      
          // 设置请求头参数
          /*
           参数一:只要设置HTTP请求头的Range属性, 就可以实现从指定位置开始下载
           表示头500个字节:Range: bytes=0-499
           表示第二个500字节:Range: bytes=500-999
           表示最后500个字节:Range: bytes=-500
           表示500字节以后的范围:Range: bytes=500-
           */
          // 设置每次下载range
          // 注意这里一定要转换为integerValue ❤️🈲
          NSString *range = [NSString stringWithFormat:@"bytes:%zd-",self.currentLength];
          [request setValue:range forHTTPHeaderField:@"Range"];
      
          // 3.NSURLConnection发送请求,由于资源较大,我们需要使用代理方法分块下载
          [NSURLConnection connectionWithRequest:request delegate:self];
      }
      
      //====================================================
      // fileSize:方法
      - (NSUInteger)fileSize:(NSString *)path
      {
          NSFileManager *manager = [NSFileManager defaultManager];
          NSDictionary *attrDict = [manager attributesOfItemAtPath:path error:nil];
      
          // 注意:第一次调用该方法时,由于还未开始下载,所以没有文件,是null,通过字典取出来的size也是空,服务器不识别,服务器不能默认文件大小是0,只能我们自己转换为integerValue
          return [attrDict[NSFileSize] integerValue];
      }
      // cacheDir方法
      - (NSString *)cacheDir
      {
          // 1.获取cache目录
          NSString *dir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
          return [dir stringByAppendingPathComponent:[self lastPathComponent]];
      }
      

    3.2文件上传

    3.2.1复杂的文件上传格式

    • 设置请求头

      [request setValue:@"multipart/form-data; boundary=分割线" forHTTPHeaderField:@"Content-Type"];
      
      • 代码

        // 1.使用HTTP中的post方法发送请求
        NSURL *urlPost = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
        
        // 2.创建可变request
        NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:urlPost];
        
        // 1⃣️设置上传请求头/请求方法(默认是get)
        requestM.HTTPMethod = @"POST";
        NSString *contentType = @"multipart/form-data; boundary=----seperator"; 
                            // multipart/form-data表示请求为上传请求; boundary=分割线,可以使任意中文
        [requestM setValue:contentType forHTTPHeaderField:@"Content-Type"];
        
    • 设置请求体

      • 文件参数

        --分割线\r\n
        Content-Disposition: form-data; name="参数名"; filename="文件名"\r\n
        Content-Type: 文件的MIMEType\r\n
        \r\n
        文件数据
        \r\n
        
        文件上传.png
        • 代码

          // 2⃣️设置请求体
          NSMutableData *httpBody = [NSMutableData data];
          
          // 设置文件参数
          [httpBody appendData:[@"------seperator" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
                          /* \r\n区别❤️
                           >\r是将当前位置移到本行开头,而\n是换行
                           严格点说, 如果只用\r, 则将当前位置移到本行开头, 但是不换行. 如果只用\n, 则换行, 但当前位置不变.
                           用C编程的话, 如果用标准输出(printf)或文本方式打开的写文件(fprintf), 用\n足够了, 这不是因为二者作用相同, 而是C的库函数会在\n前自动加上一个\r. 用其他语言编程必须注意这个问题.
                           */
          /*
           name:对应服务端接收的字段类型(服务端参数的名称)
           filename:告诉服务端当前的文件的名称(就是告诉服务端用什么名称保存当前上传的文件)
           */
          [httpBody appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"videos.plist\"" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          
          [httpBody appendData:[@"Content-Type: application/octet-stream" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          
          UIImage *image = [UIImage imageNamed:@"abc"];
          NSData *imageData = UIImagePNGRepresentation(image);
          [httpBody appendData:imageData];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          
      • 非文件参数

        --分割线\r\n
        Content-Disposition: form-data; name="参数名"\r\n
        \r\n
        参数值
        \r\n
        
        • 代码

          // 设置非文件参数
          [httpBody appendData:[@"------seperator" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          // name : 对应服务端接收的字段类型(服务端参数的名称)
          [httpBody appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          
          [httpBody appendData:[@"PJ" dataUsingEncoding:NSUTF8StringEncoding]];
          [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
          
          
      • 结束标记

        参数结束的标记
        --分割线--\r\n // 最后一个分割线可有可无
        
        • 代码

          // 设置结束符号
          [httpBody appendData:[@"------seperator--" dataUsingEncoding:NSUTF8StringEncoding]];
          
          //=====================上传=================
          // 如果是普通的请求体,直接将参数转换为二进制就OK了!❤️上传文件请求体蛋疼....
          requestM.HTTPBody = httpBody;
          // 3.sendAsync..request
          [NSURLConnection sendAsynchronousRequest:requestM queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
              NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
          }];
          
    • 注意事项

      • 请求体请求头分割线前面多两个--
      • 结束标记请求体后面多两个--

    3.2.2上传文件格式简化

    • 宏的抽取o(╯□╰)o

    4.其他

    4.1压缩与解压

    • 框架:ZipArchive

    • 压缩

      • 1.creatZipWithPaths
      • 2.creatZipWithDir
      //1. createZipWithPaths
      /*
       参数一:创建的压缩路径
       参数二:需要压缩的文件路径数组
       */  
      NSArray *arr = @[
                   @"/Users/PlwNs/Desktop/Snip20150908_1.png",
                   @"/Users/PlwNs/Desktop/Snip20150908_2.png",
                   @"/Users/PlwNs/Desktop/Snip20150908_3.png"
                   ];
      if ([Main createZipFileAtPath:@"/Users/PlwNs/Desktop/pj.zip" withFilesAtPaths:arr]) {
          NSLog(@"压缩成功");
      }
      //2. createZipWithDir
      /*
       参数一:创建的压缩路径
       参数二:需要压缩的文件夹路径
       */
      if ([Main createZipFileAtPath:@"/Users/PlwNs/Desktop/pj.zip" withContentsOfDirectory:@"/Users/PlwNs/Desktop/pj"]) {
         NSLog(@"压缩成功");
      }
      
      
    • 解压

      • unzipFileAtPath

        /*
        参数一:需要解压的文件
        参数二:解压路径
        */
        if ([Main unzipFileAtPath:@"/Users/PlwNs/Desktop/pj.zip" toDestination:@"/Users/PlwNs/Desktop/pj"]) {
          NSLog(@"解压成功");
        }
        // 注意: 如果利用cocoaPods集成, 名称叫做:SSZipArchive (0.3.2)
        

    4.2MIMETYPE

    • 为什么要获得MIME

      • 文件上传时需要用到MIMEType(Content-Type)

        // 拼接请求体时,用到MIMEType
        [httpBody appendData:[@"Content-Type: application/octet-stream" dataUsingEncoding:NSUTF8StringEncoding]];
        
      • 文件的类型不一样, 那么content-type的值也不一样

        • 如果不知道数据时什么类型, 直接传application/octet-stream(万能类型)即可
        • 开发中为了节省资源,尽量要获得真实的MIMETYPE的!❤️
    • 如何获得MIMEType

      - (NSString *)MIMETypeWithPath:(NSString *)path
      {
          // 1.url
          //注意这里个是绝对路径.不可以用来获取本地文件信息
          //    NSURL *url = [NSURL URLWithString:path];
          NSURL *url = [NSURL fileURLWithPath:path]; // 本地资源路径
      
          // 2.request
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
      
          // 3.sendSync
          NSURLResponse *response = nil;
          [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
      
          // 4.return mime
          return response.MIMEType;
      }
      
    
    | 类型   | 文件拓展名            | MIMEType               | 
    | ---- | ---------------- | ---------------------- | 
    | 图片| png              | image/png              | 
    |  ... | bmp\dib          | image/bmp              | 
    | ...  | jpe\jpeg\jpg     | image/jpeg             | 
    | ...  | gif               | image/gif              | 
    | 多媒体  | mp3              | audio/mpeg             | 
    | ...  | mp4\mpg4\m4vmp4v | video/mp4              | 
    | 文本   | js               | application/javascript | 
    | ...  | pdf              | application/pdf        | 
    | ...  | text\txt         | text/plain             | 
    | ...  | json             | application/json       | 
    | ...  | xml              | text/xml               | 
    
    
    ### 4.3NSURLConnection与NSRunloop的关系
    - 测试发送请求是异步or同步, 回调方法在哪个线程执行
      - 1.请求是异步发送;
      - 2.回调方法在主线程中执行.
      
      ``` objective-c
      - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
      {
         // 1.创建一个get请求的url
          NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
      
          // 2.request
          NSURLRequest *request = [NSURLRequest requestWithURL:url];
      
          // 3.发送请求
          //    [NSURLConnection connectionWithRequest:request delegate:self];
          [[NSURLConnection alloc] initWithRequest:request delegate:self];
      
          NSLog(@"%s",__func__);
      
        /*有结果可见:
           1.由于还未下载完,就打印-[ViewController touchesBegan:withEvent:],所以是异步发送请求;
           2.代理方法(回调方法)在主线程中执行,系统默认,考虑到我们可能会在这些回调方法中刷新UI,所以默认安排在主线程;
           2015-09-08 16:44:39.259 15-NSURLConnection和NSRunLoop[4493:1058916] -[ViewController touchesBegan:withEvent:]
           2015-09-08 16:44:39.413 15-NSURLConnection和NSRunLoop[4493:1058916] <NSThread: 0x7f8d6b406870>{number = 1, name = main}
         .........
           */
      
      }
      //=====  #pragma mark - NSURLConnectionDataDelegate ========
      - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
      {
          NSLog(@"%@",[NSThread currentThread]);
      
      }
      ......
    
    
    • 更改回调方法到子线程中执行

      // 1.创建一个get请求的url
      NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
      
      // 2.request
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      
      // 3.发送请求
         // [NSURLConnection connectionWithRequest:request delegate:self];
      NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
      
      // 更改回调方法执行的线程->子线程❤️
      [conn setDelegateQueue:[[NSOperationQueue alloc] init]];
      
      // 4.开始发送请求
      // 如果创建完NSURLConnection,就直接发送请求,而后再将回调方法加入子线程,显然这是不合逻辑的!
      [conn start];
      /*结果可见:
      2015-09-08 17:04:48.732 15-NSURLConnection和NSRunLoop[4638:1067036] <NSThread: 0x7fe22a54c4d0>{number = 3, name = (null)}
           2015-09-08 17:04:48.733 15-NSURLConnection和NSRunLoop[4638:1067037] <NSThread: 0x7fe22a62d0b0>{number = 4, name = (null)}
           2015-09-08 17:04:48.736 15-NSURLConnection和NSRunLoop[4638:1067036] <NSThread: 0x7fe22a54c4d0>{number = 3, name = (null)}
           .............
      */
      
      • 疑问:NSURLConnection对象属于局部变量,为什么还可以让其代理不断的去执行代理回调方法?😖
        • 因为:initWithRequest:/ connectionWithRequest: 等方法创建出来NSURLConnection对象后,系统会默认将其加入当前NSRunloop中,所以NSURLConnection对象不会被销毁;
    • 证明系统会默认将创建出来 NSURLConnection对象加入currentRunloop!

      • 设计思路: 在子线程中创建NSURLConnection对象,如果系统默认会将该对象加入currentRunloop, 就会造成代理方法没办法执行. 因为子线程默认是不开启RunLoop.❤️

         - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
          { 
            // 子线程中发送请求
            dispatch_async(dispatch_get_global_queue(0, 0), ^{  
            // 1.创建一个get请求的url
          
            NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
          
            // 2.request
          
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
          
            // 3.发送请求
          
            // 手动创建RunLoop!
          
            // 这里因为发送了请求,无需再设置source❤️
          
            NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
          
            //    [NSURLConnection connectionWithRequest:request delegate:self];
          
           [[NSURLConnection alloc] initWithRequest:request delegate:self];
          
            [runLoop run];
          
            /* 手动开启RunLoop结果
          
             2015-09-08 17:15:59.761 15-NSURLConnection和NSRunLoop[4750:1072239] <NSThread: 0x7fc069f47aa0>{number = 3, name = (null)}
          
             2015-09-08 17:15:59.762 15-NSURLConnection和NSRunLoop[4750:1072239] <NSThread: 0x7fc069f47aa0>{number = 3, name = (null)}
          
             2015-09-08 17:15:59.763 15-NSURLConnection和NSRunLoop[4750:1072239] <NSThread: 0x7fc069f47aa0>{number = 3, name = (null)}
          
             .......
          
             */
        
         // 无打印
         /*
         因为:❤️❤️
         1.对于由
         initWithRequest:
         connectionWithRequest:
         创建出来的NSURLConnection对象,系统默认会把他加入到当前线程;
         2.如果当前线程为子线程,那么没有开启NSRunLoop,所以,NSURLConnection对象直接死掉,无法持续下载;
         3.但是如果使用start开启NSURLConnection对象请求, 那么系统会将NSURLConnection添加到当前线程runloop的默认模式下, 如果当前线程的runloop不存在, 那么系统内部会自动创建一个!
         4.如果没有start,那么系统不会自动创建NSRunloop,需要手动创建,否则无法正常下载.
         */
        
         });
        

    }
    ​```

    相关文章

      网友评论

      • manajay:Content-Type: application/octet-stream
        使用NSInputStream这种方式上传大文件, 请求是发起了一次请求还是多次?
        SoftKnife:@manajay 一次,
        SoftKnife:@manajay 一次

      本文标题:2.1 请求相关及其问题

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