• iOS NSURLConnection和异步网络请求


    在日常应用中,我们往往使用AFNetworking等第三方库来实现网络请求部分。这篇文章会简要地介绍一下如何使用NSURLConnection来进行异步的网络请求。

    我们先看一个小demo

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        NSString *urlStr = @"http://www.baidu.com";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
        
        //从这个试验可以看出,connection的函数在 mainrunloop运行for循环时根本无法被调用,由此可见,这里的connection是在mainThread中运行的。
        NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        
        for(int i = 0 ;i<10000;i++)
        {
            NSLog(@"%d",i);
        }
        
        NSLog(@"for end==========");
    }
    
    
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        NSLog(@"good!!!!!!!!");
    }

    看下输入

    2014-05-05 10:34:18.861 UrlConnectionASyncTest[9988:60b] 9997
    2014-05-05 10:34:18.862 UrlConnectionASyncTest[9988:60b] 9998
    2014-05-05 10:34:18.862 UrlConnectionASyncTest[9988:60b] 9999
    2014-05-05 10:34:18.862 UrlConnectionASyncTest[9988:60b] for end==========
    2014-05-05 10:34:18.865 UrlConnectionASyncTest[9988:60b] good!!!!!!!!

    查看苹果的文档会发现如下的解释

    By default, a connection is scheduled on the current thread in the default mode when it is created. If you create a connection with the initWithRequest:delegate:startImmediately: method and provide NO for the startImmediately parameter, you can instead schedule the connection on an operation queue before starting it with the start method.
    
    You cannot reschedule a connection after it has started.

    这就是说,如果你仅仅通过在主线程中使用initWithRequest:delegate:方法创建一个connection对象,它会默认地加入到mainThread中,这样当数据返回时,会在main thread中执行,这就会影响UI的刷新。这种connection就是不是同步connection,不同于同步网络请求函数sendSynchronousRequest,但是它的回调函数会在main thread中执行,会影响main thread中的其他函数执行。

    下面是官方文档对NSURLConnection请求数据的3中方法的总结:

    To retrieve the contents of a URL synchronously: In code that runs exclusively on a background thread, you can call sendSynchronousRequest:returningResponse:error: to perform an HTTP request. This call returns when the request completes or an error occurs. For more details, see Retrieving Data Synchronously.
    
    To retrieve the contents of a URL using a completion handler block: If you do not need to monitor the status of a request, but merely need to perform some operation when the data has been fully received, you can call sendAsynchronousRequest:queue:completionHandler:, passing a block to handle the results. For more details, see Retrieving Data Using a Completion Handler Block.
    
    To retrieve the contents of a URL using a delegate object: Create a delegate class that implements at least the following delegate methods: connection:didReceiveResponse:, connection:didReceiveData:, connection:didFailWithError:, and connectionDidFinishLoading:. The supported delegate methods are defined in the NSURLConnectionDelegate, NSURLConnectionDownloadDelegate, and NSURLConnectionDataDelegate protocols.

    那么如何创建一个在其他thread中执行回调函数的connection呢?系统提供了2套方法,

    第一套是使用类方法,sendAsynchronousRequest:queue:completionHandler:

    第二套是使用几个对象方法,顺序如下

    1.使用initWithRequest:delegate:startImmediately:生成一个不立即开始的connnection
    
    2.通过scheduleInRunLoop:forMode: 或者 setDelegateQueue: 设置回调方法运行的thread,推荐使用第二个。
    
    3.调用start开始connection请求。

    下面给出一个demo

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        NSString *urlStr = @"http://www.baidu.com";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
    
        //从这个试验可以看出,connection的函数在 mainrunloop运行for循环时根本无法被调用,由此可见,这里的connection是在mainThread中运行的。
        // NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    
        NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    
        [con setDelegateQueue:[[NSOperationQueue alloc] init]];
        [con start];
        
        for(int i = 0 ;i<10000;i++)
        {
            NSLog(@"%d",i);
        }
        
        NSLog(@"for end==========");
    }
    
    
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
      //  NSLog(@"data is %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        NSLog(@"good!!!!!!!!");
    }

    结果如下

    2014-05-05 11:23:15.129 UrlConnectionASyncTest[10147:60b] 344
    2014-05-05 11:23:15.129 UrlConnectionASyncTest[10147:60b] 345
    2014-05-05 11:23:15.129 UrlConnectionASyncTest[10147:60b] 346
    2014-05-05 11:23:15.129 UrlConnectionASyncTest[10147:60b] 347
    2014-05-05 11:23:15.129 UrlConnectionASyncTest[10147:60b] 348
    2014-05-05 11:23:15.129 UrlConnectionASyncTest[10147:60b] 349
    2014-05-05 11:23:15.130 UrlConnectionASyncTest[10147:60b] 350
    2014-05-05 11:23:15.134 UrlConnectionASyncTest[10147:4207] good!!!!!!!!
    2014-05-05 11:23:15.143 UrlConnectionASyncTest[10147:60b] 351
    2014-05-05 11:23:15.144 UrlConnectionASyncTest[10147:60b] 352
    2014-05-05 11:23:15.144 UrlConnectionASyncTest[10147:4207] good!!!!!!!!
    2014-05-05 11:23:15.144 UrlConnectionASyncTest[10147:60b] 353
    2014-05-05 11:23:15.144 UrlConnectionASyncTest[10147:60b] 354
    2014-05-05 11:23:15.144 UrlConnectionASyncTest[10147:60b] 355
    2014-05-05 11:23:15.145 UrlConnectionASyncTest[10147:60b] 356

    可以看出connection的回调函数已经不再main thread中执行了!

  • 相关阅读:
    Numpy入门
    Numpy入门
    Spring源码之IoC原理
    LeetCode之连续子数组的最大和
    剑指Offer之从1到n整数中1出现的次数
    剑指Offer之最小的k个数
    剑指Offer之字符串的排列
    剑指Offer之二叉搜索树与双向链表
    剑指Offer之二叉树中和为某一值的路径
    剑指Offer之二叉搜索树的后序遍历序列
  • 原文地址:https://www.cnblogs.com/breezemist/p/3708808.html
Copyright © 2020-2023  润新知