你的位置:首页 > 操作系统

[操作系统]多种方式实现文件下载功能


(1)使用 NSURLConnection 直接方式

(2)使用 NSURLConnection 代理方式

(3)使用 NSURLSession 直接方式

(4)使用 NSURLSession 代理方式

(5)使用 AFNetworking 方式

 

附加功能:

使用 AFNetworking 中的 AFNetworkReachabilityManager 相关操作来检查网络情况:

  1. AFNetworkReachabilityStatusReachableViaWiFi:Wi-Fi 网络下

  2. AFNetworkReachabilityStatusReachableViaWWAN:2G/3G/4G 蜂窝移动网络下

  3. AFNetworkReachabilityStatusNotReachable:未连接网络

 

效果如下:

 

 

 

ViewController.h

1 #import <UIKit/UIKit.h>2 3 @interface ViewController : UITableViewController4 @property (copy, nonatomic) NSArray *arrSampleName;5 6 - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName;7 8 @end 

ViewController.m

 1 #import "ViewController.h" 2 #import "NSURLConnectionViewController.h" 3 #import "NSURLConnectionDelegateViewController.h" 4 #import "NSURLSessionViewController.h" 5 #import "NSURLSessionDelegateViewController.h" 6 #import "AFNetworkingViewController.h" 7  8 @interface ViewController () 9 - (void)layoutUI;10 @end11 12 @implementation ViewController13 - (void)viewDidLoad {14   [super viewDidLoad];15   16   [self layoutUI];17 }18 19 - (void)didReceiveMemoryWarning {20   [super didReceiveMemoryWarning];21   // Dispose of any resources that can be recreated.22 }23 24 - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName {25   if (self = [super initWithStyle:UITableViewStyleGrouped]) {26     self.navigationItem.title = @"多种方式实现文件下载功能";27     self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];28     29     _arrSampleName = arrSampleName;30   }31   return self;32 }33 34 - (void)layoutUI {35 }36 37 #pragma mark - UITableViewController相关方法重写38 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {39   return 0.1;40 }41 42 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {43   return 1;44 }45 46 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {47   return [_arrSampleName count];48 }49 50 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {51   static NSString *cellIdentifier = @"cell";52   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];53   if (!cell) {54     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];55   }56   cell.textLabel.text = _arrSampleName[indexPath.row];57   return cell;58 }59 60 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {61   switch (indexPath.row) {62     case 0: {63       NSURLConnectionViewController *connectionVC = [NSURLConnectionViewController new];64       [self.navigationController pushViewController:connectionVC animated:YES];65       break;66     }67     case 1: {68       NSURLConnectionDelegateViewController *connectionDelegateVC = [NSURLConnectionDelegateViewController new];69       [self.navigationController pushViewController:connectionDelegateVC animated:YES];70       break;71     }72     case 2: {73       NSURLSessionViewController *sessionVC = [NSURLSessionViewController new];74       [self.navigationController pushViewController:sessionVC animated:YES];75       break;76     }77     case 3: {78       NSURLSessionDelegateViewController *sessionDelegateVC = [NSURLSessionDelegateViewController new];79       [self.navigationController pushViewController:sessionDelegateVC animated:YES];80       break;81     }82     case 4: {83       AFNetworkingViewController *networkingVC = [AFNetworkingViewController new];84       [self.navigationController pushViewController:networkingVC animated:YES];85       break;86     }87     default:88       break;89   }90 }91 92 @end 

PrefixHeader.pch

1 #define kFileURLStr @"http://files.cnblogs.com/files/huangjianwu/metro_demo使用Highcharts实现图表展示.zip"2 3 #define kTitleOfNSURLConnection @"使用 NSURLConnection 直接方式"4 #define kTitleOfNSURLConnectionDelegate @"使用 NSURLConnection 代理方式"5 #define kTitleOfNSURLSession @"使用 NSURLSession 直接方式"6 #define kTitleOfNSURLSessionDelegate @"使用 NSURLSession 代理方式"7 #define kTitleOfAFNetworking @"使用 AFNetworking 方式"8 9 #define kApplication [UIApplication sharedApplication] 

UIButton+BeautifulButton.h

 1 #import <UIKit/UIKit.h> 2  3 @interface UIButton (BeautifulButton) 4 /** 5  * 根据按钮文字颜色,返回对应文字颜色的圆角按钮 6  * 7  * @param tintColor 按钮文字颜色;nil 的话就为深灰色 8 */ 9 - (void)beautifulButton:(UIColor *)tintColor;10 11 @end 

UIButton+BeautifulButton.m

 1 #import "UIButton+BeautifulButton.h" 2  3 @implementation UIButton (BeautifulButton) 4  5 - (void)beautifulButton:(UIColor *)tintColor { 6   self.tintColor = tintColor ?: [UIColor darkGrayColor]; 7   self.layer.masksToBounds = YES; 8   self.layer.cornerRadius = 10.0; 9   self.layer.borderColor = [UIColor grayColor].CGColor;10   self.layer.borderWidth = 1.0;11 }12 13 @end 

NSURLConnectionViewController.h

1 #import <UIKit/UIKit.h>2 3 @interface NSURLConnectionViewController : UIViewController4 @property (strong, nonatomic) IBOutlet UILabel *lblFileName;5 @property (strong, nonatomic) IBOutlet UILabel *lblMessage;6 @property (strong, nonatomic) IBOutlet UIButton *btnDownloadFile;7 8 @end 

NSURLConnectionViewController.m

 1 #import "NSURLConnectionViewController.h" 2 #import "UIButton+BeautifulButton.h" 3  4 @interface NSURLConnectionViewController () 5 - (void)layoutUI; 6 - (void)saveDataToDisk:(NSData *)data; 7 @end 8  9 @implementation NSURLConnectionViewController10 11 - (void)viewDidLoad {12   [super viewDidLoad];13   14   [self layoutUI];15 }16 17 - (void)didReceiveMemoryWarning {18   [super didReceiveMemoryWarning];19   // Dispose of any resources that can be recreated.20 }21 22 - (void)layoutUI {23   self.navigationItem.title = kTitleOfNSURLConnection;24   self.view.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.000];25   26   [_btnDownloadFile beautifulButton:nil];27 }28 29 - (void)saveDataToDisk:(NSData *)data {30   //数据接收完保存文件;注意苹果官方要求:下载数据只能保存在缓存目录(/Library/Caches)31   NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];32   savePath = [savePath stringByAppendingPathComponent:_lblFileName.text];33   [data writeToFile:savePath atomically:YES]; //writeToFile: 方法:如果 savePath 文件存在,他会执行覆盖34 }35 36 - (IBAction)downloadFile:(id)sender {37   _lblMessage.text = @"下载中...";38   39   NSString *fileURLStr = kFileURLStr;40   //编码操作;对应的解码操作是用 stringByRemovingPercentEncoding 方法41   fileURLStr = [fileURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];42   NSURL *fileURL = [NSURL URLWithString:fileURLStr];43   44   //创建请求45   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL];46   47   //创建连接;Apple 提供的处理一般请求的两种方法,他们不需要进行一系列的 NSURLConnectionDataDelegate 委托协议方法操作,简洁直观48   //方法一:发送一个同步请求;不建议使用,因为当前线程是主线程的话,会造成线程阻塞,一般比较少用49 //  NSURLResponse *response;50 //  NSError *connectionError;51 //  NSData *data = [NSURLConnection sendSynchronousRequest:request52 //                     returningResponse:&response53 //                           error:&connectionError];54 //  if (!connectionError) {55 //    [self saveDataToDisk:data];56 //    NSLog(@"保存成功");57 //    58 //    _lblMessage.text = @"下载完成";59 //  } else {60 //    NSLog(@"下载失败,错误信息:%@", connectionError.localizedDescription);61 //    62 //    _lblMessage.text = @"下载失败";63 //  }64   65   //方法二:发送一个异步请求66   [NSURLConnection sendAsynchronousRequest:request67                     queue:[NSOperationQueue mainQueue]68              completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {69                if (!connectionError) {70                   [self saveDataToDisk:data];71                  NSLog(@"保存成功");72                  73                  _lblMessage.text = @"下载完成";74                  75                } else {76                  NSLog(@"下载失败,错误信息:%@", connectionError.localizedDescription);77                  78                  _lblMessage.text = @"下载失败";79                 }80               }];81 }82 83 @end 

NSURLConnectionViewController.xib

 1 <??> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> 3   <dependencies> 4     <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/> 5   </dependencies> 6   <objects> 7     <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NSURLConnectionViewController"> 8       <connections> 9         <outlet property="btnDownloadFile" destination="mwt-p9-tRE" id="ZVc-6S-ES3"/>10         <outlet property="lblFileName" destination="dlB-Qn-eOO" id="NdS-9n-7KX"/>11         <outlet property="lblMessage" destination="qlQ-nM-BXU" id="tRe-SR-AQE"/>12         <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>13       </connections>14     </placeholder>15     <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>16     <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">17       <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>18       <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>19       <subviews>20         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="metro_demo使用Highcharts实现图表展示.zip" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dlB-Qn-eOO">21           <rect key="frame" x="145" y="104" width="309.5" height="18"/>22           <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>23           <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>24           <nil key="highlightedColor"/>25         </label>26         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mwt-p9-tRE">27           <rect key="frame" x="250" y="520" width="100" height="40"/>28           <constraints>29             <constraint firstAttribute="width" constant="100" id="I5D-tA-ffH"/>30             <constraint firstAttribute="height" constant="40" id="Y8C-D4-IVr"/>31           </constraints>32           <state key="normal" title="下载">33             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>34           </state>35           <connections>36             <action selector="downloadFile:" destination="-1" eventType="touchUpInside" id="MK4-Yk-IOk"/>37           </connections>38         </button>39         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qlQ-nM-BXU">40           <rect key="frame" x="145" y="140" width="37.5" height="18"/>41           <fontDescription key="fontDescription" type="system" pointSize="15"/>42           <color key="textColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/>43           <nil key="highlightedColor"/>44           <userDefinedRuntimeAttributes>45             <userDefinedRuntimeAttribute type="string" keyPath="text" value=""/>46           </userDefinedRuntimeAttributes>47         </label>48       </subviews>49       <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>50       <constraints>51         <constraint firstAttribute="centerX" secondItem="dlB-Qn-eOO" secondAttribute="centerX" id="gNK-NO-rth"/>52         <constraint firstItem="dlB-Qn-eOO" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="104" id="hwU-O2-Fed"/>53         <constraint firstAttribute="centerX" secondItem="mwt-p9-tRE" secondAttribute="centerX" id="teN-3t-8Gc"/>54         <constraint firstItem="qlQ-nM-BXU" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="140" id="w3g-ej-P18"/>55         <constraint firstItem="dlB-Qn-eOO" firstAttribute="leading" secondItem="qlQ-nM-BXU" secondAttribute="leading" constant="0.5" id="wMU-pU-z9f"/>56         <constraint firstAttribute="bottom" secondItem="mwt-p9-tRE" secondAttribute="bottom" constant="40" id="yBq-He-Jv8"/>57       </constraints>58     </view>59   </objects>60 </document>

View Code 

NSURLConnectionDelegateViewController.h

 1 #import <UIKit/UIKit.h> 2  3 @interface NSURLConnectionDelegateViewController : UIViewController 4 @property (strong, nonatomic) NSMutableData *mDataReceive; 5 @property (assign, nonatomic) NSUInteger totalDataLength; 6  7 @property (strong, nonatomic) IBOutlet UILabel *lblFileName; 8 @property (strong, nonatomic) IBOutlet UIProgressView *progVDownloadFile; 9 @property (strong, nonatomic) IBOutlet UILabel *lblMessage;10 @property (strong, nonatomic) IBOutlet UIButton *btnDownloadFile;11 12 @end 

NSURLConnectionDelegateViewController.m

 1 #import "NSURLConnectionDelegateViewController.h" 2 #import "UIButton+BeautifulButton.h" 3  4 @interface NSURLConnectionDelegateViewController () 5 - (void)layoutUI; 6 - (BOOL)isExistCacheInMemory:(NSURLRequest *)request; 7 - (void)updateProgress; 8 @end 9  10 @implementation NSURLConnectionDelegateViewController 11  12 - (void)viewDidLoad { 13   [super viewDidLoad]; 14    15   [self layoutUI]; 16 } 17  18 - (void)didReceiveMemoryWarning { 19   [super didReceiveMemoryWarning]; 20   // Dispose of any resources that can be recreated. 21 } 22  23 - (void)layoutUI { 24   self.navigationItem.title = kTitleOfNSURLConnectionDelegate; 25   self.view.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.000]; 26    27   [_btnDownloadFile beautifulButton:nil]; 28 } 29  30 - (BOOL)isExistCacheInMemory:(NSURLRequest *)request { 31   BOOL isExistCache = NO; 32   NSURLCache *cache = [NSURLCache sharedURLCache]; 33   [cache setMemoryCapacity:1024 * 1024]; //1M 34    35   NSCachedURLResponse *response = [cache cachedResponseForRequest:request]; 36   if (response != nil) { 37     NSLog(@"内存中存在对应请求的响应缓存"); 38     isExistCache = YES; 39   } 40   return isExistCache; 41 } 42  43 - (void)updateProgress { 44   NSUInteger receiveDataLength = _mDataReceive.length; 45   if (receiveDataLength == _totalDataLength) { 46     _lblMessage.text = @"下载完成"; 47     kApplication.networkActivityIndicatorVisible = NO; 48   } else { 49     _lblMessage.text = @"下载中..."; 50     kApplication.networkActivityIndicatorVisible = YES; 51     _progVDownloadFile.progress = (float)receiveDataLength / _totalDataLength; 52   } 53 } 54  55 - (IBAction)downloadFile:(id)sender { 56   /* 57    此例子更多的是希望大家了解代理方法接收响应数据的过程,实际开发中也不可能使用这种方法进行文件下载。这种下载有个致命的问题:无法进行大文件下载。因为代理方法在接收数据时虽然表面看起来是每次读取一部分响应数据,事实上它只有一次请求并且也只接收了一次服务器响应,只是当响应数据较大时系统会重复调用数据接收方法,每次将已读取的数据拿出一部分交给数据接收方法而已。在这个过程中其实早已经将响应数据全部拿到,只是分批交给开发者而已。这样一来对于几个G的文件如果进行下载,那么不用说是真机下载了,就算是模拟器恐怕也是不现实的。 58    实际开发文件下载的时候不管是通过代理方法还是静态方法执行请求和响应,我们都会分批请求数据,而不是一次性请求数据。假设一个文件有1G,那么只要每次请求1M的数据,请求1024次也就下载完了。那么如何让服务器每次只返回1M的数据呢? 59    在网络开发中可以在请求的头文件中设置一个Range信息,它代表请求数据的大小。通过这个字段配合服务器端可以精确的控制每次服务器响应的数据范围。例如指定bytes=0-1023,然后在服务器端解析Range信息,返回该文件的0到1023之间的数据的数据即可(共1024Byte)。这样,只要在每次发送请求控制这个头文件信息就可以做到分批请求。 60    当然,为了让整个数据保持完整,每次请求的数据都需要逐步追加直到整个文件请求完成。但是如何知道整个文件的大小?其实在此例子通过头文件信息获取整个文件大小,他请求整个数据,这样做对分段下载就没有任何意义了。所幸在WEB开发中我们还有另一种请求方法“HEAD”,通过这种请求服务器只会响应头信息,其他数据不会返回给客户端,这样一来整个数据的大小也就可以得到了。 61   */ 62    63    64   NSString *fileURLStr = kFileURLStr; 65   //编码操作;对应的解码操作是用 stringByRemovingPercentEncoding 方法 66   fileURLStr = [fileURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 67   NSURL *fileURL = [NSURL URLWithString:fileURLStr]; 68    69   /*创建请求 70    cachePolicy:缓存策略 71    1、NSURLRequestUseProtocolCachePolicy 协议缓存,根据 response 中的 Cache-Control 字段判断缓存是否有效,如果缓存有效则使用缓存数据否则重新从服务器请求 72    2、NSURLRequestReloadIgnoringLocalCacheData 不使用缓存,直接请求新数据 73    3、NSURLRequestReloadIgnoringCacheData 等同于 NSURLRequestReloadIgnoringLocalCacheData 74    4、NSURLRequestReturnCacheDataElseLoad 直接使用缓存数据不管是否有效,没有缓存则重新请求 75    5、NSURLRequestReturnCacheDataDontLoad 直接使用缓存数据不管是否有效,没有缓存数据则失败 76    77    timeoutInterval:超时时间设置(默认60s) 78   */ 79   NSURLRequest *request = [[NSURLRequest alloc] initWithURL:fileURL 80                          cachePolicy:NSURLRequestUseProtocolCachePolicy 81                        timeoutInterval:60.0]; 82   if ([self isExistCacheInMemory:request]) { 83     request = [[NSURLRequest alloc] initWithURL:fileURL 84                     cachePolicy:NSURLRequestReturnCacheDataDontLoad 85                   timeoutInterval:60.0]; 86   } 87    88   //创建连接,异步操作 89   NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request 90                                  delegate:self]; 91   [connection start]; //启动连接 92 } 93  94 #pragma mark - NSURLConnectionDataDelegate 95 - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { 96   NSLog(@"即将发送请求"); 97    98   return request; 99 }100 101 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {102   NSLog(@"已经接收到响应");103   104   _mDataReceive = [NSMutableData new];105   _progVDownloadFile.progress = 0.0;106   107   //通过响应头中的 Content-Length 获取到整个响应的总长度108   /*109    {110    "Accept-Ranges" = bytes;111    "Cache-Control" = "max-age=7776000";112    "Content-Length" = 592441;113    "Content-Type" = "application/x-zip-compressed";114    Date = "Wed, 02 Sep 2015 13:17:01 GMT";115    Etag = "\"d8f617371f9cd01:0\"";116    "Last-Modified" = "Mon, 01 Jun 2015 03:58:27 GMT";117    Server = "Microsoft-IIS/7.5";118    "X-Powered-By" = "ASP.NET";119    }120   */121   NSDictionary *dicHeaderField = [(NSHTTPURLResponse *)response allHeaderFields];122   _totalDataLength = [[dicHeaderField objectForKey:@"Content-Length"] integerValue];123 }124 125 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {126   NSLog(@"已经接收到响应数据,数据长度为%lu字节...", (unsigned long)[data length]);127   128   [_mDataReceive appendData:data]; //连续接收数据129   [self updateProgress]; //连续更新进度条130 }131 132 - (void)connectionDidFinishLoading:(NSURLConnection *)connection {133   NSLog(@"已经接收完所有响应数据");134   135   NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];136   savePath = [savePath stringByAppendingPathComponent:_lblFileName.text];137   [_mDataReceive writeToFile:savePath atomically:YES];138 }139 140 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {141   //如果连接超时或者连接地址错误可能就会报错142   NSLog(@"连接错误,错误信息:%@", error.localizedDescription);143   144   _lblMessage.text = @"连接错误";145 }146 147 @end

NSURLConnectionDelegateViewController.xib

 1 <??> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> 3   <dependencies> 4     <deployment identifier="iOS"/> 5     <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/> 6   </dependencies> 7   <objects> 8     <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NSURLConnectionDelegateViewController"> 9       <connections>10         <outlet property="btnDownloadFile" destination="mwt-p9-tRE" id="ZVc-6S-ES3"/>11         <outlet property="lblFileName" destination="dlB-Qn-eOO" id="vJk-jh-Y2c"/>12         <outlet property="lblMessage" destination="qlQ-nM-BXU" id="tRe-SR-AQE"/>13         <outlet property="progVDownloadFile" destination="Me3-m2-iC4" id="PtK-m7-j5N"/>14         <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>15       </connections>16     </placeholder>17     <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>18     <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">19       <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>20       <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>21       <subviews>22         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="metro_demo使用Highcharts实现图表展示.zip" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dlB-Qn-eOO">23           <rect key="frame" x="145" y="104" width="309.5" height="18"/>24           <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>25           <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>26           <nil key="highlightedColor"/>27         </label>28         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mwt-p9-tRE">29           <rect key="frame" x="250" y="520" width="100" height="40"/>30           <constraints>31             <constraint firstAttribute="width" constant="100" id="I5D-tA-ffH"/>32             <constraint firstAttribute="height" constant="40" id="Y8C-D4-IVr"/>33           </constraints>34           <state key="normal" title="下载">35             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>36           </state>37           <connections>38             <action selector="downloadFile:" destination="-1" eventType="touchUpInside" id="iGc-6N-bsZ"/>39           </connections>40         </button>41         <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Me3-m2-iC4">42           <rect key="frame" x="145" y="160" width="310" height="2"/>43           <constraints>44             <constraint firstAttribute="height" constant="2" id="I50-Zx-DwT"/>45             <constraint firstAttribute="width" constant="310" id="wdS-eD-Tkc"/>46           </constraints>47         </progressView>48         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qlQ-nM-BXU">49           <rect key="frame" x="145" y="180" width="37.5" height="18"/>50           <fontDescription key="fontDescription" type="system" pointSize="15"/>51           <color key="textColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/>52           <nil key="highlightedColor"/>53           <userDefinedRuntimeAttributes>54             <userDefinedRuntimeAttribute type="string" keyPath="text" value=""/>55           </userDefinedRuntimeAttributes>56         </label>57       </subviews>58       <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>59       <constraints>60         <constraint firstAttribute="centerX" secondItem="Me3-m2-iC4" secondAttribute="centerX" id="Ya8-bM-TaA"/>61         <constraint firstItem="Me3-m2-iC4" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="160" id="bOY-B5-is2"/>62         <constraint firstAttribute="centerX" secondItem="dlB-Qn-eOO" secondAttribute="centerX" id="gNK-NO-rth"/>63         <constraint firstItem="dlB-Qn-eOO" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="104" id="hwU-O2-Fed"/>64         <constraint firstItem="qlQ-nM-BXU" firstAttribute="leading" secondItem="Me3-m2-iC4" secondAttribute="leading" id="lus-oi-9SA"/>65         <constraint firstAttribute="centerX" secondItem="mwt-p9-tRE" secondAttribute="centerX" id="teN-3t-8Gc"/>66         <constraint firstItem="qlQ-nM-BXU" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="180" id="w3g-ej-P18"/>67         <constraint firstAttribute="bottom" secondItem="mwt-p9-tRE" secondAttribute="bottom" constant="40" id="yBq-He-Jv8"/>68       </constraints>69     </view>70   </objects>71 </document>

View Code

NSURLSessionViewController.h

1 #import <UIKit/UIKit.h>2 3 @interface NSURLSessionViewController : UIViewController4 @property (strong, nonatomic) IBOutlet UILabel *lblFileName;5 @property (strong, nonatomic) IBOutlet UILabel *lblMessage;6 @property (strong, nonatomic) IBOutlet UIButton *btnDownloadFile;7 8 @end 

NSURLSessionViewController.m

 1 #import "NSURLSessionViewController.h" 2 #import "UIButton+BeautifulButton.h" 3  4 @interface NSURLSessionViewController () 5 - (void)layoutUI; 6 @end 7  8 @implementation NSURLSessionViewController 9  10 - (void)viewDidLoad { 11   [super viewDidLoad]; 12    13   [self layoutUI]; 14 } 15  16 - (void)didReceiveMemoryWarning { 17   [super didReceiveMemoryWarning]; 18   // Dispose of any resources that can be recreated. 19 } 20  21 - (void)layoutUI { 22   self.navigationItem.title = kTitleOfNSURLSession; 23   self.view.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.000]; 24    25   [_btnDownloadFile beautifulButton:nil]; 26 } 27  28 - (IBAction)downloadFile:(id)sender { 29   _lblMessage.text = @"下载中..."; 30    31   NSString *fileURLStr = kFileURLStr; 32   //编码操作;对应的解码操作是用 stringByRemovingPercentEncoding 方法 33   fileURLStr = [fileURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 34   NSURL *fileURL = [NSURL URLWithString:fileURLStr]; 35    36   //创建请求 37   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL]; 38    39   //创建会话(这里使用了一个全局会话) 40   NSURLSession *session = [NSURLSession sharedSession]; 41    42   //创建下载任务,并且启动他;在非主线程中执行 43   NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { 44     __block void (^updateUI)(); //声明用于主线程更新 UI 的代码块 45      46     if (!error) { 47       NSLog(@"下载后的临时保存路径:%@", location); 48        49       NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 50       savePath = [savePath stringByAppendingPathComponent:_lblFileName.text]; 51       NSURL *saveURL = [NSURL fileURLWithPath:savePath]; 52       NSError *saveError; 53       NSFileManager *fileManager = [NSFileManager defaultManager]; 54       //判断是否存在旧的目标文件,如果存在就先移除;避免无法复制问题 55       if ([fileManager fileExistsAtPath:savePath]) { 56         [fileManager removeItemAtPath:savePath error:&saveError]; 57         if (saveError) { 58           NSLog(@"移除旧的目标文件失败,错误信息:%@", saveError.localizedDescription); 59            60           updateUI = ^ { 61             _lblMessage.text = @"下载失败"; 62           }; 63         } 64       } 65       if (!saveError) { 66         //把源文件复制到目标文件,当目标文件存在时,会抛出一个错误到 error 参数指向的对象实例 67         //方法一(path 不能有 file:// 前缀) 68         //        [fileManager copyItemAtPath:[location path] 69         //                   toPath:savePath 70         //                   error:&saveError]; 71          72         //方法二 73         [fileManager copyItemAtURL:location 74                    toURL:saveURL 75                   error:&saveError]; 76          77         if (!saveError) { 78           NSLog(@"保存成功"); 79            80           updateUI = ^ { 81             _lblMessage.text = @"下载完成"; 82           }; 83         } else { 84           NSLog(@"保存失败,错误信息:%@", saveError.localizedDescription); 85            86           updateUI = ^ { 87             _lblMessage.text = @"下载失败"; 88           }; 89         } 90       } 91        92     } else { 93       NSLog(@"下载失败,错误信息:%@", error.localizedDescription); 94        95       updateUI = ^ { 96         _lblMessage.text = @"下载失败"; 97       }; 98     } 99     100     dispatch_async(dispatch_get_main_queue(), updateUI); //使用主队列异步方式(主线程)执行更新 UI 的代码块101   }];102   [downloadTask resume]; //恢复线程,启动任务103 }104 105 @end 

NSURLSessionViewController.xib

 1 <??> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> 3   <dependencies> 4     <deployment identifier="iOS"/> 5     <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/> 6   </dependencies> 7   <objects> 8     <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NSURLSessionViewController"> 9       <connections>10         <outlet property="btnDownloadFile" destination="mwt-p9-tRE" id="ZVc-6S-ES3"/>11         <outlet property="lblFileName" destination="dlB-Qn-eOO" id="NdS-9n-7KX"/>12         <outlet property="lblMessage" destination="qlQ-nM-BXU" id="tRe-SR-AQE"/>13         <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>14       </connections>15     </placeholder>16     <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>17     <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">18       <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>19       <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>20       <subviews>21         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="metro_demo使用Highcharts实现图表展示.zip" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dlB-Qn-eOO">22           <rect key="frame" x="145" y="104" width="309.5" height="18"/>23           <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>24           <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>25           <nil key="highlightedColor"/>26         </label>27         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mwt-p9-tRE">28           <rect key="frame" x="250" y="520" width="100" height="40"/>29           <constraints>30             <constraint firstAttribute="width" constant="100" id="I5D-tA-ffH"/>31             <constraint firstAttribute="height" constant="40" id="Y8C-D4-IVr"/>32           </constraints>33           <state key="normal" title="下载">34             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>35           </state>36           <connections>37             <action selector="downloadFile:" destination="-1" eventType="touchUpInside" id="MK4-Yk-IOk"/>38           </connections>39         </button>40         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qlQ-nM-BXU">41           <rect key="frame" x="145" y="140" width="37.5" height="18"/>42           <fontDescription key="fontDescription" type="system" pointSize="15"/>43           <color key="textColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/>44           <nil key="highlightedColor"/>45           <userDefinedRuntimeAttributes>46             <userDefinedRuntimeAttribute type="string" keyPath="text" value=""/>47           </userDefinedRuntimeAttributes>48         </label>49       </subviews>50       <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>51       <constraints>52         <constraint firstAttribute="centerX" secondItem="dlB-Qn-eOO" secondAttribute="centerX" id="gNK-NO-rth"/>53         <constraint firstItem="dlB-Qn-eOO" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="104" id="hwU-O2-Fed"/>54         <constraint firstAttribute="centerX" secondItem="mwt-p9-tRE" secondAttribute="centerX" id="teN-3t-8Gc"/>55         <constraint firstItem="qlQ-nM-BXU" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="140" id="w3g-ej-P18"/>56         <constraint firstItem="dlB-Qn-eOO" firstAttribute="leading" secondItem="qlQ-nM-BXU" secondAttribute="leading" constant="0.5" id="wMU-pU-z9f"/>57         <constraint firstAttribute="bottom" secondItem="mwt-p9-tRE" secondAttribute="bottom" constant="40" id="yBq-He-Jv8"/>58       </constraints>59     </view>60   </objects>61 </document>

View Code 

NSURLSessionDelegateViewController.h

 1 #import <UIKit/UIKit.h> 2  3 @interface NSURLSessionDelegateViewController : UIViewController <NSURLSessionDownloadDelegate> 4 @property (strong, nonatomic) NSURLSessionDownloadTask *downloadTask; 5  6 @property (strong, nonatomic) IBOutlet UILabel *lblFileName; 7 @property (strong, nonatomic) IBOutlet UIProgressView *progVDownloadFile; 8 @property (strong, nonatomic) IBOutlet UILabel *lblMessage; 9 @property (strong, nonatomic) IBOutlet UIButton *btnDownloadFile;10 @property (strong, nonatomic) IBOutlet UIButton *btnCancel;11 @property (strong, nonatomic) IBOutlet UIButton *btnSuspend;12 @property (strong, nonatomic) IBOutlet UIButton *btnResume;13 14 @end 

NSURLSessionDelegateViewController.m

 1 #import "NSURLSessionDelegateViewController.h" 2 #import "UIButton+BeautifulButton.h" 3  4 @interface NSURLSessionDelegateViewController () 5 - (void)layoutUI; 6 - (NSURLSession *)defaultSession; 7 - (NSURLSession *)backgroundSession; 8 - (void)updateProgress:(int64_t)receiveDataLength totalDataLength:(int64_t)totalDataLength; 9 @end 10  11 @implementation NSURLSessionDelegateViewController 12  13 - (void)viewDidLoad { 14   [super viewDidLoad]; 15    16   [self layoutUI]; 17 } 18  19 - (void)didReceiveMemoryWarning { 20   [super didReceiveMemoryWarning]; 21   // Dispose of any resources that can be recreated. 22 } 23  24 - (void)layoutUI { 25   self.navigationItem.title = kTitleOfNSURLSessionDelegate; 26   self.view.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.000]; 27    28   [_btnDownloadFile beautifulButton:nil]; 29   [_btnCancel beautifulButton:[UIColor redColor]]; 30   [_btnSuspend beautifulButton:[UIColor purpleColor]]; 31   [_btnResume beautifulButton:[UIColor orangeColor]]; 32 } 33  34 - (NSURLSession *)defaultSession { 35   /* 36    NSURLSession 支持进程三种会话: 37    1、defaultSessionConfiguration:进程内会话(默认会话),用硬盘来缓存数据。 38    2、ephemeralSessionConfiguration:临时的进程内会话(内存),不会将 cookie、缓存储存到本地,只会放到内存中,当应用程序退出后数据也会消失。 39    3、backgroundSessionConfiguration:后台会话,相比默认会话,该会话会在后台开启一个线程进行网络数据处理。 40   */ 41  42   //创建会话配置「进程内会话」 43   NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; 44   sessionConfiguration.timeoutIntervalForRequest = 60.0; //请求超时时间;默认为60秒 45   sessionConfiguration.allowsCellularAccess = YES; //是否允许蜂窝网络访问(2G/3G/4G) 46   sessionConfiguration.HTTPMaximumConnectionsPerHost = 4; //限制每次最多连接数;在 iOS 中默认值为4 47    48   //创建会话 49   NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration 50                              delegate:self 51                            delegateQueue:nil]; 52   return session; 53 } 54  55 - (NSURLSession *)backgroundSession { 56   static NSURLSession *session; 57   static dispatch_once_t onceToken; 58   dispatch_once(&onceToken, ^{ //应用程序生命周期内,只执行一次;保证只有一个「后台会话」 59     //创建会话配置「后台会话」 60     NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"KMDownloadFile.NSURLSessionDelegateViewController"]; 61     sessionConfiguration.timeoutIntervalForRequest = 60.0; //请求超时时间;默认为60秒 62     sessionConfiguration.allowsCellularAccess = YES; //是否允许蜂窝网络访问(2G/3G/4G) 63     sessionConfiguration.HTTPMaximumConnectionsPerHost = 4; //限制每次最多连接数;在 iOS 中默认值为4 64     sessionConfiguration.discretionary = YES; //是否自动选择最佳网络访问,仅对「后台会话」有效 65      66     //创建会话 67     session = [NSURLSession sessionWithConfiguration:sessionConfiguration 68                         delegate:self 69                       delegateQueue:nil]; 70   }); 71   return session; 72 } 73  74 - (void)updateProgress:(int64_t)receiveDataLength totalDataLength:(int64_t)totalDataLength; { 75   dispatch_async(dispatch_get_main_queue(), ^{ //使用主队列异步方式(主线程)执行更新 UI 操作 76     if (receiveDataLength == totalDataLength) { 77       _lblMessage.text = @"下载完成"; 78       kApplication.networkActivityIndicatorVisible = NO; 79     } else { 80       _lblMessage.text = @"下载中..."; 81       kApplication.networkActivityIndicatorVisible = YES; 82       _progVDownloadFile.progress = (float)receiveDataLength / totalDataLength; 83     } 84   }); 85 } 86  87 - (IBAction)downloadFile:(id)sender { 88   NSString *fileURLStr = kFileURLStr; 89   //编码操作;对应的解码操作是用 stringByRemovingPercentEncoding 方法 90   fileURLStr = [fileURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 91   NSURL *fileURL = [NSURL URLWithString:fileURLStr]; 92    93   //创建请求 94   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL]; 95    96   //创建会话「进程内会话」;如要用「后台会话」就使用自定义的[self backgroundSession] 方法 97   NSURLSession *session = [self defaultSession]; 98    99   //创建下载任务,并且启动他;在非主线程中执行100   _downloadTask = [session downloadTaskWithRequest:request];101   [_downloadTask resume];102   103   /*104    会话任务状态105    typedef NS_ENUM(NSInteger, NSURLSessionTaskState) {106    NSURLSessionTaskStateRunning = 0, //正在执行107    NSURLSessionTaskStateSuspended = 1, //已挂起108    NSURLSessionTaskStateCanceling = 2, //正在取消109    NSURLSessionTaskStateCompleted = 3, //已完成110    } NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);111   */112 }113 114 - (IBAction)cancel:(id)sender {115   [_downloadTask cancel];116 }117 118 - (IBAction)suspend:(id)sender {119   [_downloadTask suspend];120   kApplication.networkActivityIndicatorVisible = NO;121 }122 123 - (IBAction)resume:(id)sender {124   [_downloadTask resume];125 }126 127 #pragma mark - NSURLSessionDownloadDelegate128 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {129   NSLog(@"已经接收到响应数据,数据长度为%lld字节...", totalBytesWritten);130   131   [self updateProgress:totalBytesWritten totalDataLength:totalBytesExpectedToWrite];132 }133 134 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {135   //下载文件会临时保存,正常流程下系统最终会自动清除此临时文件;保存路径目录根据会话类型而有所不同:136   //「进程内会话(默认会话)」和「临时的进程内会话(内存)」,路径目录为:/tmp,可以通过 NSTemporaryDirectory() 方法获取137   //「后台会话」,路径目录为:/Library/Caches/com.apple.nsurlsessiond/Downloads/com.kenmu.KMDownloadFile138   NSLog(@"已经接收完所有响应数据,下载后的临时保存路径:%@", location);139   140   __block void (^updateUI)(); //声明用于主线程更新 UI 的代码块141   142   NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];143   savePath = [savePath stringByAppendingPathComponent:_lblFileName.text];144   NSURL *saveURL = [NSURL fileURLWithPath:savePath];145   NSError *saveError;146   NSFileManager *fileManager = [NSFileManager defaultManager];147   //判断是否存在旧的目标文件,如果存在就先移除;避免无法复制问题148   if ([fileManager fileExistsAtPath:savePath]) {149     [fileManager removeItemAtPath:savePath error:&saveError];150     if (saveError) {151       NSLog(@"移除旧的目标文件失败,错误信息:%@", saveError.localizedDescription);152       153       updateUI = ^ {154         _lblMessage.text = @"下载失败";155       };156     }157   }158   if (!saveError) {159     //把源文件复制到目标文件,当目标文件存在时,会抛出一个错误到 error 参数指向的对象实例160     //方法一(path 不能有 file:// 前缀)161     //        [fileManager copyItemAtPath:[location path]162     //                   toPath:savePath163     //                   error:&saveError];164     165     //方法二166     [fileManager copyItemAtURL:location167                toURL:saveURL168               error:&saveError];169     170     if (!saveError) {171       NSLog(@"保存成功");172       173       updateUI = ^ {174         _lblMessage.text = @"下载完成";175       };176     } else {177       NSLog(@"保存失败,错误信息:%@", saveError.localizedDescription);178       179       updateUI = ^ {180         _lblMessage.text = @"下载失败";181       };182     }183   }184   185   dispatch_async(dispatch_get_main_queue(), updateUI); //使用主队列异步方式(主线程)执行更新 UI 的代码块186 }187 188 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {189   NSLog(@"无论下载成功还是失败,最终都会执行一次");190   191   if (error) {192     NSString *desc = error.localizedDescription;193     NSLog(@"下载失败,错误信息:%@", desc);194     195     dispatch_async(dispatch_get_main_queue(), ^{ //使用主队列异步方式(主线程)执行更新 UI 操作196       _lblMessage.text = [desc isEqualToString:@"cancelled"] ? @"下载已取消" : @"下载失败";197       kApplication.networkActivityIndicatorVisible = NO;198       _progVDownloadFile.progress = 0.0;199     });200   }201 }202 203 @end

NSURLSessionDelegateViewController.xib

 1 <??> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> 3   <dependencies> 4     <deployment identifier="iOS"/> 5     <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/> 6   </dependencies> 7   <objects> 8     <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NSURLSessionDelegateViewController"> 9       <connections> 10         <outlet property="btnCancel" destination="yMY-kU-iKL" id="QHP-ls-q8P"/> 11         <outlet property="btnDownloadFile" destination="mwt-p9-tRE" id="ZVc-6S-ES3"/> 12         <outlet property="btnResume" destination="YSM-n6-UM4" id="RyL-54-rFB"/> 13         <outlet property="btnSuspend" destination="5kz-pB-9nK" id="1Jj-zV-DXM"/> 14         <outlet property="lblFileName" destination="dlB-Qn-eOO" id="vJk-jh-Y2c"/> 15         <outlet property="lblMessage" destination="qlQ-nM-BXU" id="tRe-SR-AQE"/> 16         <outlet property="progVDownloadFile" destination="Me3-m2-iC4" id="PtK-m7-j5N"/> 17         <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> 18       </connections> 19     </placeholder> 20     <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> 21     <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT"> 22       <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> 23       <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> 24       <subviews> 25         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="metro_demo使用Highcharts实现图表展示.zip" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dlB-Qn-eOO"> 26           <rect key="frame" x="145" y="104" width="309.5" height="18"/> 27           <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> 28           <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> 29           <nil key="highlightedColor"/> 30         </label> 31         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mwt-p9-tRE"> 32           <rect key="frame" x="145" y="520" width="70" height="40"/> 33           <constraints> 34             <constraint firstAttribute="width" constant="70" id="I5D-tA-ffH"/> 35             <constraint firstAttribute="height" constant="40" id="Y8C-D4-IVr"/> 36           </constraints> 37           <state key="normal" title="下载"> 38             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> 39           </state> 40           <connections> 41             <action selector="downloadFile:" destination="-1" eventType="touchUpInside" id="iGc-6N-bsZ"/> 42           </connections> 43         </button> 44         <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Me3-m2-iC4"> 45           <rect key="frame" x="145" y="160" width="310" height="2"/> 46           <constraints> 47             <constraint firstAttribute="height" constant="2" id="I50-Zx-DwT"/> 48             <constraint firstAttribute="width" constant="310" id="wdS-eD-Tkc"/> 49           </constraints> 50         </progressView> 51         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qlQ-nM-BXU"> 52           <rect key="frame" x="145" y="180" width="37.5" height="18"/> 53           <fontDescription key="fontDescription" type="system" pointSize="15"/> 54           <color key="textColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/> 55           <nil key="highlightedColor"/> 56           <userDefinedRuntimeAttributes> 57             <userDefinedRuntimeAttribute type="string" keyPath="text" value=""/> 58           </userDefinedRuntimeAttributes> 59         </label> 60         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5kz-pB-9nK"> 61           <rect key="frame" x="305" y="520" width="70" height="40"/> 62           <constraints> 63             <constraint firstAttribute="width" constant="70" id="IOm-ve-DPG"/> 64             <constraint firstAttribute="height" constant="40" id="Kwn-EW-gDl"/> 65           </constraints> 66           <state key="normal" title="挂起"> 67             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> 68           </state> 69           <connections> 70             <action selector="suspend:" destination="-1" eventType="touchUpInside" id="O6j-t2-7Lv"/> 71           </connections> 72         </button> 73         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="YSM-n6-UM4"> 74           <rect key="frame" x="385" y="520" width="70" height="40"/> 75           <constraints> 76             <constraint firstAttribute="width" constant="70" id="LhS-5f-cG4"/> 77             <constraint firstAttribute="height" constant="40" id="kzz-1h-4DP"/> 78           </constraints> 79           <state key="normal" title="恢复"> 80             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> 81           </state> 82           <connections> 83             <action selector="resume:" destination="-1" eventType="touchUpInside" id="ms9-R9-B9B"/> 84           </connections> 85         </button> 86         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yMY-kU-iKL"> 87           <rect key="frame" x="225" y="520" width="70" height="40"/> 88           <constraints> 89             <constraint firstAttribute="height" constant="40" id="S7b-Pl-qKI"/> 90             <constraint firstAttribute="width" constant="70" id="gY7-vp-PUz"/> 91           </constraints> 92           <state key="normal" title="取消"> 93             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> 94           </state> 95           <connections> 96             <action selector="cancel:" destination="-1" eventType="touchUpInside" id="ITC-zg-bfP"/> 97           </connections> 98         </button> 99       </subviews>100       <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>101       <constraints>102         <constraint firstItem="5kz-pB-9nK" firstAttribute="centerY" secondItem="YSM-n6-UM4" secondAttribute="centerY" id="4zt-gy-k65"/>103         <constraint firstItem="qlQ-nM-BXU" firstAttribute="leading" secondItem="mwt-p9-tRE" secondAttribute="leading" id="RYu-qM-O8P"/>104         <constraint firstAttribute="centerX" secondItem="Me3-m2-iC4" secondAttribute="centerX" id="Ya8-bM-TaA"/>105         <constraint firstItem="Me3-m2-iC4" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="160" id="bOY-B5-is2"/>106         <constraint firstItem="yMY-kU-iKL" firstAttribute="centerY" secondItem="5kz-pB-9nK" secondAttribute="centerY" id="dBh-1A-sIk"/>107         <constraint firstItem="YSM-n6-UM4" firstAttribute="leading" secondItem="5kz-pB-9nK" secondAttribute="trailing" constant="10" id="fYW-Jv-ro2"/>108         <constraint firstAttribute="centerX" secondItem="dlB-Qn-eOO" secondAttribute="centerX" id="gNK-NO-rth"/>109         <constraint firstItem="dlB-Qn-eOO" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="104" id="hwU-O2-Fed"/>110         <constraint firstItem="mwt-p9-tRE" firstAttribute="centerY" secondItem="yMY-kU-iKL" secondAttribute="centerY" id="lGv-fH-Fh7"/>111         <constraint firstItem="qlQ-nM-BXU" firstAttribute="leading" secondItem="Me3-m2-iC4" secondAttribute="leading" id="lus-oi-9SA"/>112         <constraint firstItem="5kz-pB-9nK" firstAttribute="leading" secondItem="yMY-kU-iKL" secondAttribute="trailing" constant="10" id="oge-T7-1td"/>113         <constraint firstItem="qlQ-nM-BXU" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="180" id="w3g-ej-P18"/>114         <constraint firstItem="yMY-kU-iKL" firstAttribute="leading" secondItem="mwt-p9-tRE" secondAttribute="trailing" constant="10" id="xCX-1F-xOv"/>115         <constraint firstAttribute="bottom" secondItem="mwt-p9-tRE" secondAttribute="bottom" constant="40" id="yBq-He-Jv8"/>116       </constraints>117     </view>118   </objects>119 </document>

View Code 

AFNetworkingViewController.h

 1 #import <UIKit/UIKit.h> 2 #import "MBProgressHUD.h" 3  4 @interface AFNetworkingViewController : UIViewController 5 @property (strong, nonatomic) MBProgressHUD *hud; 6  7 @property (strong, nonatomic) IBOutlet UILabel *lblFileName; 8 @property (strong, nonatomic) IBOutlet UILabel *lblMessage; 9 @property (strong, nonatomic) IBOutlet UIButton *btnDownloadFileByConnection;10 @property (strong, nonatomic) IBOutlet UIButton *btnDownloadFileBySession;11 12 @end 

AFNetworkingViewController.m

 1 #import "AFNetworkingViewController.h" 2 #import "AFNetworking.h" 3 #import "UIButton+BeautifulButton.h" 4  5 @interface AFNetworkingViewController () 6 - (void)showAlert:(NSString *)msg; 7 - (void)checkNetwork; 8 - (void)layoutUI; 9 - (NSMutableURLRequest *)downloadRequest; 10 - (NSURL *)saveURL:(NSURLResponse *)response deleteExistFile:(BOOL)deleteExistFile; 11 - (void)updateProgress:(int64_t)receiveDataLength totalDataLength:(int64_t)totalDataLength; 12 @end 13  14 @implementation AFNetworkingViewController 15  16 - (void)viewDidLoad { 17   [super viewDidLoad]; 18    19   [self layoutUI]; 20 } 21  22 - (void)didReceiveMemoryWarning { 23   [super didReceiveMemoryWarning]; 24   // Dispose of any resources that can be recreated. 25 } 26  27 - (void)showAlert:(NSString *)msg { 28   UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"网络情况" 29                           message:msg 30                          delegate:self 31                      cancelButtonTitle:nil 32                      otherButtonTitles:@"确定", nil]; 33   [alert show]; 34 } 35  36 - (void)checkNetwork { 37   NSURL *baseURL = [NSURL URLWithString:@"http://www.baidu.com/"]; 38   AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL]; 39    40   NSOperationQueue *operationQueue = manager.operationQueue; 41   [manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { 42     switch (status) { 43       case AFNetworkReachabilityStatusReachableViaWiFi: 44         [self showAlert:@"Wi-Fi 网络下"]; 45         [operationQueue setSuspended:NO]; 46         break; 47       case AFNetworkReachabilityStatusReachableViaWWAN: 48         [self showAlert:@"2G/3G/4G 蜂窝移动网络下"]; 49         [operationQueue setSuspended:YES]; 50         break; 51       case AFNetworkReachabilityStatusNotReachable: 52       default: 53         [self showAlert:@"未连接网络"]; 54         [operationQueue setSuspended:YES]; 55         break; 56     } 57   }]; 58    59   [manager.reachabilityManager startMonitoring]; 60 } 61  62 - (void)layoutUI { 63   self.navigationItem.title = kTitleOfAFNetworking; 64   self.view.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.000]; 65    66   //条件表达式中,「?:」可以表示在条件不成立的情况,才使用后者赋值,否则使用用于条件判断的前者赋值 67   //以下语句等同于:UIButton *btn = _btnDownloadFileByConnection ? _btnDownloadFileByConnection : [UIButton new]; 68   //在 .NET 中,相当于使用「??」;在 JavaScript 中,相当于使用「||」来实现这种类似的判断 69   UIButton *btn = _btnDownloadFileByConnection ?: [UIButton new]; 70   [btn beautifulButton:nil]; 71   [_btnDownloadFileBySession beautifulButton:[UIColor orangeColor]]; 72    73   //进度效果 74   _hud = [[MBProgressHUD alloc] initWithView:self.view]; 75   _hud.mode = MBProgressHUDModeDeterminate; 76   _hud.labelText = @"下载中..."; 77   [_hud hide:YES]; 78   [self.view addSubview:_hud]; 79    80   //检查网络情况 81   [self checkNetwork]; 82 } 83  84 - (NSMutableURLRequest *)downloadRequest { 85   NSString *fileURLStr = kFileURLStr; 86   //编码操作;对应的解码操作是用 stringByRemovingPercentEncoding 方法 87   fileURLStr = [fileURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 88   NSURL *fileURL = [NSURL URLWithString:fileURLStr]; 89    90   //创建请求 91   NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL]; 92   return request; 93 } 94  95 - (NSURL *)saveURL:(NSURLResponse *)response deleteExistFile:(BOOL)deleteExistFile { 96   NSString *fileName = response ? [response suggestedFilename] : _lblFileName.text; 97    98   //方法一 99 //  NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];100 //  savePath = [savePath stringByAppendingPathComponent:fileName];101 //  NSURL *saveURL = [NSURL fileURLWithPath:savePath];102   103   //方法二104   NSURL *saveURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];105   saveURL = [saveURL URLByAppendingPathComponent:fileName];106   NSString *savePath = [saveURL path];107   108   if (deleteExistFile) {109     NSError *saveError;110     NSFileManager *fileManager = [NSFileManager defaultManager];111     //判断是否存在旧的目标文件,如果存在就先移除;避免无法复制问题112     if ([fileManager fileExistsAtPath:savePath]) {113       [fileManager removeItemAtPath:savePath error:&saveError];114       if (saveError) {115         NSLog(@"移除旧的目标文件失败,错误信息:%@", saveError.localizedDescription);116       }117     }118   }119   120   return saveURL;121 }122 123 - (void)updateProgress:(int64_t)receiveDataLength totalDataLength:(int64_t)totalDataLength; {124   dispatch_async(dispatch_get_main_queue(), ^{ //使用主队列异步方式(主线程)执行更新 UI 操作125     _hud.progress = (float)receiveDataLength / totalDataLength;126     127     if (receiveDataLength == totalDataLength) {128       _lblMessage.text = receiveDataLength < 0 ? @"下载失败" : @"下载完成";129       kApplication.networkActivityIndicatorVisible = NO;130       [_hud hide:YES];131     } else {132       _lblMessage.text = @"下载中...";133       kApplication.networkActivityIndicatorVisible = YES;134       [_hud show:YES];135     }136   });137 }138 139 - (IBAction)downloadFileByConnection:(id)sender {140   //创建请求141   NSMutableURLRequest *request = [self downloadRequest];142   143   //创建请求操作144   AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];145   NSString *savePath = [[self saveURL:nil deleteExistFile:NO] path];146   147   [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {148     NSLog(@"已经接收到响应数据,数据长度为%lld字节...", totalBytesRead);149     150     [self updateProgress:totalBytesRead totalDataLength:totalBytesExpectedToRead];151   }];152   153   [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {154     NSLog(@"已经接收完所有响应数据");155     156     NSData *data = (NSData *)responseObject;157     [data writeToFile:savePath atomically:YES]; //responseObject 的对象类型是 NSData158     159     [self updateProgress:100 totalDataLength:100];160   } failure:^(AFHTTPRequestOperation *operation, NSError *error) {161     NSLog(@"下载失败,错误信息:%@", error.localizedDescription);162     163     [self updateProgress:-1 totalDataLength:-1];164   }];165   166   //启动请求操作167   [operation start];168 }169 170 - (IBAction)downloadFileBySession:(id)sender {171   //创建请求172   NSMutableURLRequest *request = [self downloadRequest];173   174   //创建会话配置「进程内会话」175   NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];176   sessionConfiguration.timeoutIntervalForRequest = 60.0; //请求超时时间;默认为60秒177   sessionConfiguration.allowsCellularAccess = YES; //是否允许蜂窝网络访问(2G/3G/4G)178   sessionConfiguration.HTTPMaximumConnectionsPerHost = 4; //限制每次最多连接数;在 iOS 中默认值为4179   180   //创建会话管理器181   AFURLSessionManager *sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:sessionConfiguration];182   183   //创建会话下载任务,并且启动他;在非主线程中执行184   NSURLSessionDownloadTask *task = [sessionManager185                    downloadTaskWithRequest:request186                    progress:nil187                    destination:^ NSURL*(NSURL *targetPath, NSURLResponse *response) {188                      //当 sessionManager 调用 setDownloadTaskDidFinishDownloadingBlock: 方法,并且方法代码块返回值不为 nil 时(优先级高),下面的两句代码是不执行的(优先级低)189                      NSLog(@"下载后的临时保存路径:%@", targetPath);190                      return [self saveURL:response deleteExistFile:YES];191                    } completionHandler:^ (NSURLResponse *response, NSURL *filePath, NSError *error) {192                      if (!error) {193                        NSLog(@"下载后的保存路径:%@", filePath); //为上面代码块返回的路径194                        195                        [self updateProgress:100 totalDataLength:100];196                      } else {197                        NSLog(@"下载失败,错误信息:%@", error.localizedDescription);198                        199                        [self updateProgress:-1 totalDataLength:-1];200                      }201                      202                      [_hud hide:YES];203                    }];204   205   //类似 NSURLSessionDownloadDelegate 的方法操作206   //- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;207   [sessionManager setDownloadTaskDidWriteDataBlock:^ (NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {208     NSLog(@"已经接收到响应数据,数据长度为%lld字节...", totalBytesWritten);209     210     [self updateProgress:totalBytesWritten totalDataLength:totalBytesExpectedToWrite];211   }];212   213   //- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location;214   [sessionManager setDownloadTaskDidFinishDownloadingBlock:^ NSURL*(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location) {215     NSLog(@"已经接收完所有响应数据,下载后的临时保存路径:%@", location);216     return [self saveURL:nil deleteExistFile:YES];217   }];218   219   [task resume];220 }221 222 @end 

AFNetworkingViewController.xib

 1 <??> 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES"> 3   <dependencies> 4     <deployment identifier="iOS"/> 5     <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/> 6   </dependencies> 7   <objects> 8     <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AFNetworkingViewController"> 9       <connections>10         <outlet property="btnDownloadFileByConnection" destination="IkH-un-SOz" id="gDd-6X-uxU"/>11         <outlet property="btnDownloadFileBySession" destination="mwt-p9-tRE" id="5Qk-Zm-V3w"/>12         <outlet property="lblFileName" destination="dlB-Qn-eOO" id="NdS-9n-7KX"/>13         <outlet property="lblMessage" destination="qlQ-nM-BXU" id="tRe-SR-AQE"/>14         <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>15       </connections>16     </placeholder>17     <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>18     <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">19       <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>20       <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>21       <subviews>22         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="metro_demo使用Highcharts实现图表展示.zip" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dlB-Qn-eOO">23           <rect key="frame" x="145" y="104" width="309.5" height="18"/>24           <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>25           <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>26           <nil key="highlightedColor"/>27         </label>28         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="mwt-p9-tRE">29           <rect key="frame" x="175" y="520" width="250" height="40"/>30           <constraints>31             <constraint firstAttribute="width" constant="250" id="I5D-tA-ffH"/>32             <constraint firstAttribute="height" constant="40" id="Y8C-D4-IVr"/>33           </constraints>34           <state key="normal" title="基于 NSURLSession 的下载">35             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>36           </state>37           <connections>38             <action selector="downloadFileBySession:" destination="-1" eventType="touchUpInside" id="z6s-cq-dag"/>39           </connections>40         </button>41         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qlQ-nM-BXU">42           <rect key="frame" x="145" y="140" width="37.5" height="18"/>43           <fontDescription key="fontDescription" type="system" pointSize="15"/>44           <color key="textColor" red="0.0" green="0.50196081399917603" blue="1" alpha="1" colorSpace="calibratedRGB"/>45           <nil key="highlightedColor"/>46           <userDefinedRuntimeAttributes>47             <userDefinedRuntimeAttribute type="string" keyPath="text" value=""/>48           </userDefinedRuntimeAttributes>49         </label>50         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IkH-un-SOz">51           <rect key="frame" x="174" y="460" width="250" height="40"/>52           <constraints>53             <constraint firstAttribute="width" constant="250" id="3a7-Og-iWa"/>54             <constraint firstAttribute="height" constant="40" id="mc0-yK-hWE"/>55           </constraints>56           <state key="normal" title="基于 NSURLConnection 的下载">57             <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>58           </state>59           <connections>60             <action selector="downloadFileByConnection:" destination="-1" eventType="touchUpInside" id="1ko-jP-kCo"/>61           </connections>62         </button>63       </subviews>64       <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>65       <constraints>66         <constraint firstItem="mwt-p9-tRE" firstAttribute="top" secondItem="IkH-un-SOz" secondAttribute="bottom" constant="20" id="Sye-JW-gux"/>67         <constraint firstAttribute="centerX" secondItem="dlB-Qn-eOO" secondAttribute="centerX" id="gNK-NO-rth"/>68         <constraint firstItem="dlB-Qn-eOO" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="104" id="hwU-O2-Fed"/>69         <constraint firstAttribute="centerX" secondItem="IkH-un-SOz" secondAttribute="centerX" constant="1" id="lF1-Yf-Axs"/>70         <constraint firstAttribute="centerX" secondItem="mwt-p9-tRE" secondAttribute="centerX" id="teN-3t-8Gc"/>71         <constraint firstItem="qlQ-nM-BXU" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="140" id="w3g-ej-P18"/>72         <constraint firstItem="dlB-Qn-eOO" firstAttribute="leading" secondItem="qlQ-nM-BXU" secondAttribute="leading" constant="0.5" id="wMU-pU-z9f"/>73         <constraint firstAttribute="bottom" secondItem="mwt-p9-tRE" secondAttribute="bottom" constant="40" id="yBq-He-Jv8"/>74       </constraints>75     </view>76   </objects>77 </document>

View Cod 

AppDelegate.h

1 #import <UIKit/UIKit.h>2 3 @interface AppDelegate : UIResponder <UIApplicationDelegate>4 5 @property (strong, nonatomic) UIWindow *window;6 @property (strong, nonatomic) UINavigationController *navigationController;7 8 @end 

AppDelegate.m

 1 #import "AppDelegate.h" 2 #import "ViewController.h" 3  4 @interface AppDelegate () 5  6 @end 7  8 @implementation AppDelegate 9 10 11 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {12   _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];13   ViewController *viewController = [[ViewController alloc]14                    initWithSampleNameArray:@[ kTitleOfNSURLConnection,15                                  kTitleOfNSURLConnectionDelegate,16                                  kTitleOfNSURLSession,17                                  kTitleOfNSURLSessionDelegate,18                                  kTitleOfAFNetworking]];19   _navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];20   _window.rootViewController = _navigationController;21   //[_window addSubview:_navigationController.view]; //当_window.rootViewController关联时,这一句可有可无22   [_window makeKeyAndVisible];23   return YES;24 }25 26 - (void)applicationWillResignActive:(UIApplication *)application {27 }28 29 - (void)applicationDidEnterBackground:(UIApplication *)application {30 }31 32 - (void)applicationWillEnterForeground:(UIApplication *)application {33 }34 35 - (void)applicationDidBecomeActive:(UIApplication *)application {36 }37 38 - (void)applicationWillTerminate:(UIApplication *)application {39 }40 41 @end