zoukankan      html  css  js  c++  java
  • NSURLSession使用说明及后台工作流程分析

    NSURLSession简介

    NSURLSession是iOS7中新的网络接口,它与咱们熟悉的NSURLConnection是并列的。在程序在前台时,NSURLSession与NSURLConnection可以互为替代工作。注意,如果用户强制将程序关闭,NSURLSession会断掉。

    NSURLSession提供的功能:

    • 通过URL将数据下载到内存
    • 通过URL将数据下载到文件系统
    • 将数据上传到指定URL
    • 在后台完成上述功能

    工作流程

    如果我们需要利用NSURLSession进行数据传输我们需要:

    1. 创建一个NSURLSessionConfiguration,用于第二步创建NSSession时设置工作模式和网络设置:

    工作模式分为:

    • 一般模式(default):工作模式类似于原来的NSURLConnection,可以使用缓存的Cache,Cookie,鉴权。
    • 及时模式(ephemeral):不使用缓存的Cache,Cookie,鉴权。
    • 后台模式(background):在后台完成上传下载,创建Configuration对象的时候需要给一个NSString的ID用于追踪完成工作的Session是哪一个(后面会讲到)。

    网络设置:参考NSURLConnection中的设置项。

      1. 创建一个NSURLSession,系统提供了两个创建方法:

    • sessionWithConfiguration:
    • sessionWithConfiguration:delegate:delegateQueue:

        第一个粒度较低就是根据刚才创建的Configuration创建一个Session,系统默认创建一个新的OperationQueue处理Session的消息。

        第二个粒度比较高,可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便。

      2.创建一个NSURLRequest调用刚才的NSURLSession对象提供的Task函数,创建一个NSURLSessionTask。

      根据职能不同Task有三种子类:

    • NSURLSessionUploadTask:上传用的Task,传完以后不会再下载返回结果;
    • NSURLSessionDownloadTask:下载用的Task;
    • NSURLSessionDataTask:可以上传内容,上传完成后再进行下载。

      得到的Task,调用resume开始工作。

      3. 如果是细粒度的Session调用,Session与Delegate会在指定的OperationQueue中进行交互,以咱们下载例子,交互过程的顺序图如下(假如不需要鉴权,即非HTTPS请求):

     

      5. 当不再需要连接调用Session的invalidateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBecomeInvalidWithError:这个事件。Delegate收到这个事件之后会被解引用。

      6. 如果是一个BackgroundSession,在Task执行的时候,用户切到后台,Session会和ApplicationDelegate做交互。当程序切到后台后,在BackgroundSession中的Task还会继续下载,这部分文档叙述比较少,现在分三个场景分析下Session和Application的关系:

    • 当加入了多个Task,程序没有切换到后台。

      这种情况Task会按照NSURLSessionConfiguration的设置正常下载,不会和ApplicationDelegate有交互。

    • 当加入了多个Task,程序切到后台,所有Task都完成下载。

      在切到后台之后,Session的Delegate不会再收到,Task相关的消息,直到所有Task全都完成后,系统会调用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回调,之后“汇报”下载工作,对于每一个后台下载的Task调用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的话)和URLSession:task:didCompleteWithError:(成功或者失败都会调用)。

      之后调用Session的Delegate回调URLSessionDidFinishEventsForBackgroundURLSession:。

      注意:在ApplicationDelegate被唤醒后,会有个参数ComplietionHandler,这个参数是个Block,这个参数要在后面Session的Delegate中didFinish的时候调用一下,如下:

    @implementation APLAppDelegate

    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier

      completionHandler:(void (^)())completionHandler

    {

        BLog();

        /*

         Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed).

         */

          self.backgroundSessionCompletionHandler = completionHandler;

    }

    //……

    @end

    //Session的Delegate

    @implementation APLViewController

    - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session

    {

        APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];

        if (appDelegate.backgroundSessionCompletionHandler) {

            void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;

            appDelegate.backgroundSessionCompletionHandler = nil;

            completionHandler();

        }

        NSLog(@"All tasks are finished");

    }

    @end

    • 当加入了多个Task,程序切到后台,下载完成了几个Task,然后用户又切换到前台。(程序没有退出)

      切到后台之后,Session的Delegate仍然收不到消息。在下载完成几个Task之后再切换到前台,系统会先汇报已经下载完成的Task的情况,然后继续下载没有下载完成的Task,后面的过程同第一种情况。

    • 当加入了多个Task,程序切到后台,几个Task已经完成,但还有Task还没有下载完的时候关掉强制退出程序,然后再进入程序的时候。(程序退出了)

      最后这个情况比较有意思,由于程序已经退出了,后面没有下完Session就不在了后面的Task肯定是失败了。但是已经下载成功的那些Task,新启动的程序也没有听“汇报”的机会了。经过实验发现,这个时候之前在NSURLSessionConfiguration设置的NSString类型的ID起作用了,当ID相同的时候,一旦生成Session对象并设置Delegate,马上可以收到上一次关闭程序之前没有汇报工作的Task的结束情况(成功或者失败)。但是当ID不相同,这些情况就收不到了,因此为了不让自己的消息被别的应用程序收到,或者收到别的应用程序的消息,起见ID还是和程序的Bundle名称绑定上比较好,至少保证唯一性

    总结

      就像前面说的,在普通的应用场景下NSURLSession与NSURLConnection相比没有什么优势,但是在程序切换到后台之后Background的Session就显得更加灵活了。

      另外,现在主流的网络开发框架AFNetworking已经更新到了2.0(只支持iOS 6 / iOS 7),其中最重要的一个更新就是添加了NSURLSession相关的支持。虽然就我现在(2013.10.13)看到他们的源码中,还没有完全的支持后台的Session(或者说没有考虑全我上述的后台情况),但是大家有兴趣可以关注一下他们后续的更新情况。

    参考资料:

    苹果官方文档:

    https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW1

    注意:苹果又开始不更新Xcode 中的文档,然后悄悄在网上更新了,大家请关注相关文档最后的更新时间,以最新的为准

    AFNetworking 2.0:

    https://github.com/AFNetworking/AFNetworking/

     
     
     
     
  • 相关阅读:
    HDU 1358 Period (KMP)
    POJ 1042 Gone Fishing
    Csharp,Javascript 获取显示器的大小的几种方式
    css text 自动换行的实现方法 Internet Explorer,Firefox,Opera,Safar
    Dynamic Fonts动态设置字体大小存入Cookie
    CSS Image Rollovers翻转效果Image Sprites图片精灵
    CSS three column layout
    css 自定义字体 Internet Explorer,Firefox,Opera,Safari
    颜色选择器 Color Picker,Internet Explorer,Firefox,Opera,Safar
    CSS TextShadow in Safari, Opera, Firefox and more
  • 原文地址:https://www.cnblogs.com/biosli/p/iOS_Network_URL_Session.html
Copyright © 2011-2022 走看看