zoukankan      html  css  js  c++  java
  • iOS开发系列-NSURLConnection

    概述

    NSURLConnection是负责发送请求,建立客户端与服务端的连接。发送数据给服务器,并收集来自服务器的响应数据。其中NSURLRequest类是用来封装一个请求,包含NSURL对象、请求方法、请求头、请求超时等信息。它有一个子类NSMutableURLRequest。
    发送一个请求具体的步骤:
    * 创建一个NSURL对象,设置请求路径
    * 入NSURL创建的一个NSRULRequest对象,设置请求头、请求体。
    * 使用NSURLConnection发送网络请求

    NSURLConnection发送请求

    发送同步请求

    NSURLConnection类方法发送同步请求

    + (nullable NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse * _Nullable * _Nullable)response error:(NSError **)error
    

    第二个参数传入的响应头指针,真实的类型是NSHTTPURLResponse。返回值NSData为服务端响应体的数据。该函数是同步的(线程阻塞)。

    发送异步请求

    NSURLConnection类方法发送异步请求

    + (void)sendAsynchronousRequest:(NSURLRequest*) request
                              queue:(NSOperationQueue*) queue
                  completionHandler:(void (^)(NSURLResponse* _Nullable response, NSData* _Nullable data, NSError* _Nullable connectionError)) handler 
    

    第二个参数queue决定方法的回调Block的线程。Block中的response真实类型为NSHTTPURLResponse是服务端响应的响应头信息,data为响应体。

    代理方式发送异步请求

    NSURLConnection也可以使用Delegate方式发送异步请求
    NSURLConnection有三个方法设置代理发送异步请求

    - (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate
    + (nullable NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate
    

    这个两个方法底层会主动调用NSURLConnection的start方法发送请求,无须手动调用start方法。

    - (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate startImmediately:(BOOL)startImmediately
    

    这个方法的startImmediately参数用户决定是否立即发送请求,如果传递为NO,我们需要拿到返回的NSURLConnection对象手动调用start方法发送请求。

    通过代理方式发送异步请求,代理遵守协议并不是遵守NSURLConnectionDelegate 而是NSURLConnectionDataDelegate。NSURLConnectionDataDelegate协议遵守NSURLConnectionDelegate协议。

    协议方法

    // 接受到服务器的数据
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    // 接受到服务器的数据 如果数据量较大 该方法会多次被调用
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    // 请求完成
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    // 请求失败(比如请求超时 默认是60s)
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    

    delegate异步请求适合服务端返回较大的数据场景。

    POST请求

    POST请求的的参数是放在请求体中,NSURLRequest默认是GET请求。因此需要它的子类NSMutableURLRequest创建一个可变的请求。

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"]];
        
        // 设置POST请求 注意POST都为大写
        request.HTTPMethod = @"POST";
        // 设置请求出参数
        request.HTTPBody = [@"username=coderhong&pwd=12345" dataUsingEncoding:NSUTF8StringEncoding];
        // 设置请求超时(服务在超时时间内服务端还未返回数据 默认60s)
        request.timeoutInterval = 10;
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            
            NSLog(@"------%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        }];
    

    其实完整的HTTP请求包含了请求头、请求体。使用NSURLConnection发送请求,默认帮我们设置了请求头信息。我们可以通过NSMutableURLRequest对象设置请求头、设置请求超时时间。

    // 设置请求超时(服务在超时时间内服务端还未返回数据 默认60s)
    request.timeoutInterval = 10;
        
    // 设置请求头
    [request setValue:@"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" forHTTPHeaderField:@"User-Agent"];
    

    URL包含中的解决方案

    如果URL中包含了中文需要对URL中的中文进行转码。调用字符串的下面方法,生成转码后的URL字符串。如果是POST请求调用dataUsingEncoding:方法转成二进制内部已经进行了中文转码可以无需另外处理。

    - (nullable NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc
    

    NSURLConnection与runloop

    NSURLConnection使用代理发送请求,默认代理方法是在主线程。我们可以通过NSURLConnection实例设置回调在子线程

    // 发送请求
    NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
    // 设置代理方法的执行线程
    [conn setDelegateQueue: [[NSOperationQueue alloc] init]];
    

    NSURLConnection发送请求后,一直在等待服务端一点一点的给它数据,所以应该有一个运行循环一直在等待服务器给它数据。也就是说NSURLConnection是在runloop接受服务器返回的数据的。其实NSURLConnection内部会关联当前线程的runloop。如果将发送的请求代码放在子线程中代理的方法不会执行,代码如下:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 发送请求
            NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
            // 设置代理方法的执行线程
            [conn setDelegateQueue: [[NSOperationQueue alloc] init]];
        });
    

    因为此时NSURLConnection关联当前的子线程runloop默认是没有开启的,因此需要手动开启子线程的runloop

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 发送请求
            NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
            // 设置代理方法的执行线程
            [conn setDelegateQueue: [[NSOperationQueue alloc] init]];
            
            // 开启当前子线程的runloop
            [[NSRunLoop currentRunLoop] run];
        });
    

    补充:如果我们想强制停止一个runloop需要CoreFoundation中函数。

    void CFRunLoopStop(CFRunLoopRef rl);
    

    注意:如果通过上面函数停止runloop,在开启runloop使用CFRunLoopRun()函数开启。不要使用[[NSRunLoop currentRunLoop] run];方式开启。

  • 相关阅读:
    Atitit 常用比较复杂的图像滤镜 attilax大总结
    Atitit usrQBM1603短信验证码规范
    Atitit usrQBM2331 参数格式化规范
    Atitit 函数式编程与命令式编程的区别attilax总结  qbf
    atitit 短信接口规范与短信解决方案.docx
    atitit  验证码理论与概览与 验证码规范 解决方案.docx
    Atiti  attilax主要成果与解决方案与案例rsm版 v4
    Atitit 作用域的理解attilax总结
    Atitit cms
    Atitit 图片 验证码生成attilax总结
  • 原文地址:https://www.cnblogs.com/CoderHong/p/8893835.html
Copyright © 2011-2022 走看看