1.HTTP网络编程

HTTP网络编程

1. 基本概念
- 客户端(Client):手机移动应用。
- 服务端(Server):为客户端提供服务、数据、资源的机器。
- 请求(Request):客户端向服务器索取数据的一种行为。
- 响应(Response):服务器对客户端的请求作出的反应(一般为返回数据给客户端)。

2. URL(Uniform Resource Locator:统一资源定位符)
- URL:就是资源的地址、位置。互联网上的每一个资源都有一个唯一的URL。
- 基本格式:协议://主机地址/路径
- 协议:不同的协议代表着不同的资源查找方式、资源传输方式。
- 主机地址:存放着资源的主机(服务器)的IP地址/域名。
- 路径:资源在主机中的具体位置。

3. HTTP协议
(1) 作用:
- 全称Hypertext Transfer Protocol:超文本传输协议。
- 规定客户端与服务器之间的数据传输格式。
- 让客户端和服务器有效的进行数据沟通。

(2) GET和POST:
- GET和POST的主要区别表现在数据传递上
- GET:1.在请求URL后面以“?”的形式跟上发给服务器的参数,多个参数之间用&隔开(如http://www.test.com/login?username=123&pwd=234);2.浏览器和服务器对URL长度有限制,URL可带参数受限制(通常不能超过1K)。
- POST:发给服务器的参数全部在请求体中(理论上,POST传递的数据量没有限制(具体看服务器的处理能力))。
- 推荐选择:1.POST:大量数据、安全性要求高、增删改查处理;2.GET:索取数据/数据查询。

(3) 通信过程
1. 请求:客户端向服务器索取数据。
2. 响应:服务器返回客户端相应的数据。

(4) 请求的方案
这里写图片描述

(5)常见响应吗
这里写图片描述

2.1 网络配置

这里写图片描述

2.2 NSURLConnect网络连接

  • NSURL:设置请求地址
  • NSURLRequest:创建请求对象(默认GET方式)
  • NSURLConnect:网络连接对象
  • NSMutableURLRequest:NSURLRequest子类,可用于修改请求方式
  • didFailWithError:错误处理协议
  • didReceiveData:获取数据协议
  • connectionDidFinishLoading:加载数据完成协议

(1)NSMutableURLRequest常用方法:
这里写图片描述

#import "NSConnectionViewController.h"
#define LIST_URL @"http://new.api.bandu.cn/book/listofgrade?grade_id=2"

//NSURLConnectionDataDelegate:连接服务器的普通代理协议,作为错误处理等协议完成;
//NSURLConnectionDelegate:连接服务器对象的数据代理协议,当回传数据时使用的协议;
@interface NSConnectionViewController ()<NSURLConnectionDataDelegate, NSURLConnectionDelegate>
{
    //定义一个URL连接对象,通过网络地址,可以进行连接工作
    NSURLConnection *_connect;

    //接受服务器传回的数据
    NSMutableData *_data;
}
@end

@implementation NSConnectionViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view setBackgroundColor:[UIColor whiteColor]];

    _data = [[NSMutableData alloc] init];
    // Do any additional setup after loading the view.

    NSArray *arr = @[@"同步请求", @"block异步", @"delegate异步"];
    NSUInteger count = [arr count];
    for(int i=0; i<count; i++){
        UIButton *btn = [UIButton buttonWithType: UIButtonTypeSystem];
        btn.frame = CGRectMake(80, 70+i*40, 50, 30);

        [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchDown];

        [btn setTitle:arr[i] forState:UIControlStateNormal];

        btn.tag = 100 + i;

        [btn sizeToFit];

        [self.view addSubview: btn];
    }
}

- (void)btnAction :(UIButton *)sender
{
    // 1.创建NSURL对象
    NSURL *url = [NSURL URLWithString:LIST_URL];

    // 2.创建NSURLRequst 默认GET
    NSURLRequest *request = [NSURLRequest requestWithURL: url];

    switch (sender.tag) {
        case 100:   //同步请求
        {
            NSError *error = nil;
            NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];

            if(error == nil){
                NSLog(@"request: %@", request);

                NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

                NSLog(@"---%@", str);
            }
            else{
                NSLog(@"--错误信息: %@", error);
            }

            NSLog(@"线程:%@", [NSThread currentThread]);
            break;
        }

        case 101:   //block方式异步请求
        {
            //[NSOperationQueue mainQueue]为主队列
            //[[NSOperationQueue alloc] init]子队列
            [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {

                if(connectionError == nil){
                    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                    NSLog(@"str = %@", str);
                }
                else{
                    NSLog(@"error = %@", connectionError);
                }

                //查看线程
                NSLog(@"currentThread = %@", [NSThread currentThread]);
            }];

            break;
        }

        case 102:   //delegate请求
        {
            //创建一个网络连接对象
            //参数一:连接的请求对象
            //参数二:代理对象,用来实现回传数据的代理协议
            _connect = [NSURLConnection connectionWithRequest: request delegate:self];

            break;
        }

        default:
            break;
    }
}

#pragma mark -
#pragma mark -- Delegate --
//处理错误信息的代理协议
//如果有任何连接错误,调用此协议,运行错误的打印查看
//P1:连接对象
//P2:错误信息
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    NSLog(@"error: = %@", error);
}

//处理服务器的响应码
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    //将响应码转化为http响应码
    NSHTTPURLResponse *res = (NSHTTPURLResponse *) response;

    switch (res.statusCode) {
        case 200:
            NSLog(@"连接成功!服务器政策!");
            break;
        case 400:
            NSLog(@"客户端请求语法错误,服务器无法解析");
            break;
        case 404:
            NSLog(@"服务器正常开启,没有找到连接地址网页或数据");
            break;
        case 500:
            NSLog(@"服务器宕机或关机");
            break;
        default:
            break;
    }
}

//接受服务器回传数据时调用
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //将每次回传的数据连接起来
    [_data appendData:data];
}

- (void) connectionDidFinishLoading:(NSURLConnection *)connection{
    //将二进制数据转化为字符串(解析)
    NSLog(@"baidu page = %@", [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]);

    //查看线程
    NSLog(@"currentThread = %@", [NSThread currentThread]);
}

2.3 NSURLSession网络连接

(1)使用步骤
- 1.创建NSURLSession的会话
- 2.根据会话创建Task
- 3.执行Task

(2)常见方法
- suspend:暂停
- resume:恢复
- cancel:取消
- cancelByProducingResumeData:(void(^)………):取消下载任务时使用

#import "NSURLSessionViewController.h"

#define LIST_URL @"http://new.api.bandu.cn/book/listofgrade?grade_id=2"
#define IMAGE_URL @"http://pic33.nipic.com/20130916/3420027_192919547000_2.jpg"
#define VIDER_URL @"http://war3down1.uuu9.com/war3/201609/201609131028.rar"

@interface NSURLSessionViewController ()<
NSURLSessionDataDelegate,
NSURLSessionDownloadDelegate
>
{
    //接收数据
    NSMutableData *_data;

    UIImageView *imageView;

    //区分下载
    BOOL isDonwloadImage;
}

@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
@property (nonatomic, strong) NSData *downloadData; //已下载的数据量

@end

@implementation NSURLSessionViewController

-(NSURLSession *)session{
    if(!_session){
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    }

    return _session;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view setBackgroundColor:[UIColor whiteColor]];

    self.downloadData = [[NSData alloc] init];

    imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 400, 200, 100)];

    NSArray *arr = @[@"POST", @"GET", @"Delegate", @"donwload", @"开始下载", @"暂停下载", @"继续下载", @"取消下载"];
    NSUInteger count = [arr count];
    for(int i=0; i<count; i++){
        UIButton *btn = [UIButton buttonWithType: UIButtonTypeSystem];

        btn.frame = CGRectMake(80, 100+i*50, 50, 40);

        [btn setTitle:arr[i] forState:UIControlStateNormal];

        btn.tag = 100 + i;

        [btn sizeToFit];

        [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview: btn];
    }
    // Do any additional setup after loading the view.
}

-(void)btnAction : (UIButton *)btn
{
    switch (btn.tag) {
        case 100:   //post
            [self POST];
            break;
        case 101:   //GET
            [self GET];
            break;
        case 102:   //delegate
            [self delegateRequest];
            break;
        case 103:   //download
            [self downloadImage];
            break;
        case 104:   //start download
        {
            isDonwloadImage = NO;

            //根据会话创建下载任务
            self.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString: VIDER_URL]];

            //启动任务
            [self.downloadTask resume];
            break;
        }
        case 105:   //Pause download
            //可以继续恢复下载
            [self.downloadTask suspend];
            break;
        case 106:   //continue download
        {
            //如果在暂停时候没有保存数据则不需要下面语句
//            self.downloadTask = [self.session downloadTaskWithResumeData: self.downloadData];
            [self.downloadTask resume];
            break;
        }
        case 107:   //stop download
        {
            //取消任务,不能继续下载
            [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
                //resumeData 代表当前下载了多少数据
                //如果不需要保存数据则无需赋值
//                self.downloadData = resumeData;
            }];
            break;
        }
        default:
            break;
    }
}


//POST请求方式
-(void)POST
{
    //设置地址
    NSURL *url = [NSURL URLWithString: @"http://new.api.bandu.cn/book/listofgrade"];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url];

    //设置请求方式
    request.HTTPMethod = @"POST";

    //设置请求体
    request.HTTPBody = [@"grade_id=2" dataUsingEncoding:NSUTF8StringEncoding];

    // 1.创建Session
    NSURLSession *session = [NSURLSession sharedSession];

    // 2.根据会话创建任务
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        NSLog(@"线程: %@", [NSThread currentThread]);
        if(error == nil)
        {
            //解析数据
            NSDictionary *jsoDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error: &error];
            NSLog(@"%@", jsoDic);
        }

        //回归到主线程

        NSLog(@"POST完毕");
    }];

    // 3.启动任务
    [dataTask resume];
}


//GET请求方式
- (void)GET
{
    //设置地址
    NSURL *url = [NSURL URLWithString: LIST_URL];

    //封装一个请求类
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    // 1.创建Session
    NSURLSession *session = [NSURLSession sharedSession];

    // 2.根据会话创建任务
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        NSLog(@"线程: %@", [NSThread currentThread]);
        if(error == nil)
        {
            //解析数据
            NSDictionary *jsoDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error: &error];
            NSLog(@"%@", jsoDic);
        }
        else{
            NSLog(@"error: %@", error);
        }

        //回归到主线程

        NSLog(@"GET完毕");
    }];

    // 3.启动任务
    [dataTask resume];
}

//使用协议来请求数据
-(void)delegateRequest
{
    isDonwloadImage = YES;

    // 设置地址
    NSURL *url = [NSURL URLWithString: LIST_URL];

    //封装一个请求类
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    // 1.创建Session
    /*
     + (NSURLSessionConfiguration *)defaultSessionConfiguration; 默认
     + (NSURLSessionConfiguration *)ephemeralSessionConfiguration; 无痕浏览
     + (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)iddentifier 下载任务并通知
     */
    //delegateQueue:协议在哪个线程执行
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                                          delegate:self
                                                     delegateQueue:[NSOperationQueue mainQueue]];

    //根据会话创建任务
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];

    //启动任务
    [dataTask resume];
}


#pragma mark -
#pragma mark -- Delegate --
//接收服务器的响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    NSLog(@"didReceiveResponse");

    if(_data == nil){
        _data = [[NSMutableData alloc] init];
    }
    else{
        _data.length = 0;
    }

    //NSURLSessionResponseDisposition:
//    NSURLSessionResponseCancel = 0,       //请求后不接受服务器数据,默认
//    NSURLSessionResponseAllow = 1,        //允许接受服务器的数据
//    NSURLSessionResponseBecomeDownload    //转成下载任务
//    NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3,   //转成流
    completionHandler(NSURLSessionResponseAllow);
}

//接收到数据,该方法会调用调用多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
    NSLog(@"didReceiveData");

    //拼接数据
    [_data appendData:data];

    NSLog(@"%@", _data);
}

// 数据请求完成/请求错误调用的方法
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    if(error == nil){
        if(!isDonwloadImage){
            NSLog(@"下载任务完成");
        }
        else{
            id jsoDic = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableContainers error:nil];
            NSLog(@"%@", jsoDic);
        }

        NSLog(@"delegate请求完毕");
    }
    else{
        NSLog(@"error = %@", error);
    }
}

- (void)downloadImage
{
    //1.会话
    NSURLSession *session = [NSURLSession sharedSession];

    //2.根据会话创建任务
    //location:本地文件url的位置
    NSURLSessionDownloadTask *Dask = [session downloadTaskWithURL:[NSURL URLWithString:IMAGE_URL] completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        //在子线程中运行
        if(error == nil)
        {
            NSLog(@"下载图片中");
            imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL: location]];
            [self.view addSubview: imageView];
        }
    }];

    //启动
    [Dask resume];
}

#pragma mark -
#pragma mark -- 下载任务协议 --
//下载的进度
// bytesWritten:当前次下载的数据大小
// totalBytesWritten 总共下载了多少数据量
// totalBytesExpectedToWrite 总数据的大小
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    NSLog(@"已经下载了%f", 1.0 * totalBytesWritten / totalBytesExpectedToWrite);
}

// 恢复任务调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
    NSLog(@"恢复了下载任务");
}

//下载完之后 文件所在位置
-(void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    NSLog(@"下载位置:%@", location);
}

2.4 AFNetworking

  • AFHTTPSSessionManager:HTTP请求管理器
  • Success:responseObject:请求数据成功
  • Failure:error:请求数据失败
  • AFNetworkReachabilityManager:网络连接监测管理器(查看手机连接网络状态)
  • AFURLRequestSerialization:请求的数据格式(默认二进制)
  • AFURLResponseSerialization:响应的数据格式(默认JSON格式)
#import "AFNetworkingViewController.h"
#import "AFNetworking.h"
#import "Reachability.h"

#define BOOK_URL @"http://new.api.bandu.cn/book/listofgrade?grade_id=2"
#define IMAGE_URL @"http://pic33.nipic.com/20130916/3420027_192919547000_2.jpg"

@interface AFNetworkingViewController ()

@property (nonatomic, strong) Reachability *readch;

@end

@implementation AFNetworkingViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    NSArray *arr = @[@"AFNetwork监测网络状态", @"发送请求", @"下载任务", @"开启网络监测"];
    NSUInteger count = [arr count];
    for(int i=0; i<count; i++)
    {
        UIButton *btn = [UIButton buttonWithType: UIButtonTypeSystem];

        btn.frame = CGRectMake(80, 80+i*60, 50, 30);

        [btn setTitle:arr[i] forState:UIControlStateNormal];

        btn.tag = 100 + i;

        [btn sizeToFit];

        [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview: btn];
    }


    // Do any additional setup after loading the view.
}

- (void)btnAction :(UIButton *)btn
{
    switch (btn.tag) {
        case 100:
            [self AFNetMonitor];
            break;
        case 101:
            [self AFGetData];
            break;
        case 102:
            [self downloadImage];
            break;
        case 103:
            [self reachbility];
            break;
        default:
            break;
    }
}

#pragma mark -
#pragma mark -- AFNetwork网络监测 --
- (void)AFNetMonitor
{
    //检查网络连接的状态
    //AFNetworkReachabilityManager 网络连接监测管理类

    //开启网络状态监测器
    //shareManager:获得唯一的单例对象
    [[AFNetworkReachabilityManager sharedManager] startMonitoring];

    //获取网络连接的结果
    [[AFNetworkReachabilityManager sharedManager]
        setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {

            switch (status) {
                case AFNetworkReachabilityStatusNotReachable:
                    NSLog(@"没有网络连接");
                    break;
                case AFNetworkReachabilityStatusReachableViaWiFi:
                    NSLog(@"WIFI连接");
                    break;
                case AFNetworkReachabilityStatusReachableViaWWAN:
                    NSLog(@"通过移动网络,4G");
                    break;
                default:
                    NSLog(@"无法知道网络类型");
                    break;
            }
        }];
}

#pragma mark -
#pragma mark -- 苹果官方监测网络 --
- (void)reachbility
{
    NSLog(@"开启网络监测");
    // 监听通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeReadchability) name:kReachabilityChangedNotification object:nil];

    //开启网络监控
    self.readch = [Reachability reachabilityForInternetConnection];

    [self.readch startNotifier];
}

- (void)changeReadchability
{
    // NotReachable = 0,
    // ReachableViaWiFi = 2,
    // ReachableViaWWAN = 1
    switch (self.readch.currentReachabilityStatus) {
        case NotReachable:
            NSLog(@"没有网络");
            break;
        case ReachableViaWWAN:
            NSLog(@"手机连接");
            break;
        case ReachableViaWiFi:
            NSLog(@"WIFI连接");
            break;
        default:
            break;
    }
}


#pragma mark -
#pragma mark -- AFNetwork请求数据 --
- (void) AFGetData
{
    //创建http连接管理对象
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //响应序列化(响应接收到的数据)
    // AFXMLParserResponseSerializer: XML数据
    // AFJSONResponseSerializer: JSON数据
    // AFHTTPResponseSerializer: 二进制数据
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //转换编码
//    NSString *str = [BOOK_URL stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]];

    //请求体
    NSDictionary *dict = @{@"grade_id":@"2"};

    /* GET 方法获取服务器的数据
     GET 通过get方法
     P1:参数传入一个url对象
     P2:通过制定的解构传入参数
     P3:指定下载的进度条UI
     P4:下载成功数据后调用此b语法块(PP1,下载的人物线程,pp2返回的数据内容)
     P5:下载失败后调用此语法块(pp1.下载的任务线程,pp2返回的错误类型) */
    [manager GET:BOOK_URL parameters:dict progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"请求成功 ");

        NSError *error = nil;

        NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:responseObject
                                                                options:NSJSONReadingMutableLeaves
                                                                  error:&error];

        if(error == nil){
            NSLog(@"%@", jsonDic);
        }


    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败! error = %@", error);
    }];
}


#pragma mark -
#pragma mark -- AFNetwork download file --
-(void)downloadImage
{
    //定义管理器
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    // 下载任务
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:IMAGE_URL]];

    __block NSProgress *progresst = nil;

    // totalUnitCount 总共下载量
    // completedUnitCount 已下载的数据


    // progress:监测下载进度
    // block回调
    // targetPath下载后的位置
    NSURLSessionDownloadTask *task = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress){
        //监测下载进度
        progresst = downloadProgress;

        // KVO监测进度
        [progresst addObserver:self forKeyPath:@"completedUnitCount" options:NSKeyValueObservingOptionNew context:nil];

    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        NSLog(@"下载的位置%@", targetPath);

        //存放到沙盒
        NSString *location = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];

        //返回一个你想让下载的文件放置的位置
        return [NSURL fileURLWithPath: location];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        NSLog(@"filePath = %@", filePath);

        NSLog(@"error = %@", error);
    }];

    [task resume];
}

//监测下载进度
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    NSProgress *progress = (NSProgress *)object;
    NSLog(@"已经下载的进度为:%f", 1.0 * progress.completedUnitCount / progress.totalUnitCount);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值