2.1 请求相关及其问题

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,需要手动创建,否则无法正常下载.
       */
      
       });
      

}
​```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容