iOS開發非徹底指南之: 網絡請求

現現在單機版本的 APP 幾乎不復存在,咱們須要掌握如何使用 iOS/web/Android 如何發送 http/https 請求給後端服務,根據響應數據渲染頁面。本文主要介紹如何使用 iOS 創建網絡請求。html

1、網絡請求基礎使用

1. 網絡請求主流程

要實現網絡請求須要經歷以下幾個步驟:java

  1. 構造請求的 URL
  2. 建立一個網絡請求,網絡請求不指定方法默認是 GET
  3. 建立網絡管理
  4. 建立一個網絡請求任務,並處理響應信息;若有更新 UI 須要回到主線程
  5. 開啓網絡請求任務任務

一個請求百度首頁圖片的例子:ios

- (void) network{
    // 1. 建立一個url
    NSURL *url= [NSURL URLWithString: @"https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"];
    // 2. 建立一個網絡請求,網絡請求不指定方法默認是GET
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    // request.HTTPMethod = @"GET";


    // 自定義請求配置
    // NSURLSessionConfiguration *config = [[NSURLSessionConfiguration alloc] init];
    // config.timeoutIntervalForRequest= 20;// 請求超超時時間
    // //...還有不少參數
    // NSURLSession *session = [NSURLSession sessionWithConfiguration: config];
    // 3. 建立網絡管理
    NSURLSession *session = [NSURLSession sharedSession];

    // 4. 建立一個網絡任務
    /* 第一個參數 : 請求對象 第二個參數 : completionHandler回調 ( 請求完成 ["成功"or"失敗"] 的回調 ) data : 響應體信息(指望的數據) response : 響應頭信息,主要是對服務器端的描述 error : 錯誤信息 , 若是請求失敗 , 則error有值 */
    NSURLSessionDataTask *task= [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // data就是服務器返回的數據,response爲服務器的響應
        if(!error){
            // 強轉爲NSHTTPURLResponse

            NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
            if(res.statusCode == 200){
               // 更新UI必須回到主線程
                dispatch_async(dispatch_get_main_queue(), ^{
                     self.imgView.image = [UIImage imageWithData:data];
                });
            }

        }else{
            NSLog(@"報錯啦,%@",error);
        }
    }];
    // 5. 開啓任務
    [task resume];
}

複製代碼

若是你把上面的 https 請求更換成 http,你會發現以下報錯:git

報錯啦,Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x60000246d4d0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png, NSErrorFailingURLKey=http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.
複製代碼

其主要緣由是 iOS 默認使用 https 請求,而不是 http;因此會攔截 http 請求,因此會報錯。github

2. ATS 配置保證訪問 Http

要保證 iOS 可以訪問 http 請求;須要在 Info.plist 文件中新增以下配置:web

<key>NSAppTransportSecurity</key>
	<dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
複製代碼

3. GET 請求 JSON 並解析

這裏使用一個真實的環境,請求 json 數據,返回轉換成 Model 並天氣列表。主要步驟以下:編程

  1. 構建一個 url,帶中文的 url 進行轉換
  2. 建立一個網絡請求(url;
  3. 建立網絡管理
  4. 建立一個網絡任務
    • 網絡錯誤判斷
    • 將 JSON 數據 NSData 轉換成 NSDictionary(由於服務器返回的是一個{}格式的)
    • 獲取數據建立 Model
    • 回到主線程更新數據和 UI
  5. 開啓任務
#import "ViewController.h"
#import "Weather.h"
#import "WeatherCell.h"

@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, strong) NSMutableArray<Weather *> * weathers;
@property (weak, nonatomic) IBOutlet UITableView *weatherTableView;
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *indicator;

@end

@implementation ViewController

-(NSMutableArray<Weather *> *)weathers{

    if (_weathers == nil) {
        // 須要初始化weathers,防止不存在數據,調用weathers.count等報錯
        _weathers = [NSMutableArray arrayWithCapacity:7];
    }

    return _weathers;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 設置行高,防止展現高度不足
    self.weatherTableView.rowHeight = 100.0;
    // 刪除Tableview底部的空白區域
    self.weatherTableView.tableFooterView = [[UIView alloc]init];

    [self weather];
}


-(void)weather{

    //1.建立一個url
    NSString *net = @"http://v.juhe.cn/weather/index?format=2&cityname=重慶&key=2d2e6e836dbdffac56814bc4d449d507";

    //帶中文的url進行轉換
    net = [net stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

    NSURL *url = [NSURL URLWithString:net];

    //2.建立一個網絡請求(url)
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
    //request.HTTPMethod = @"POST";

    //    自定義請求配置
    //    NSURLSessionConfiguration *config = [[NSURLSessionConfiguration alloc] init];
    //    config.timeoutIntervalForRequest= 20;// 請求超超時時間
    //    //...還有不少參數
    //    NSURLSession *session = [NSURLSession sessionWithConfiguration: config];

    //3.建立網絡管理,
    NSURLSession *session = [NSURLSession sharedSession];
    //4.建立一個網絡任務
    NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        if (error) {
            NSLog(@"有錯誤");
        }
        else {
            //須要轉換成NSHTTPURLResponse
            NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
            NSLog(@"%ld", (long)res.statusCode);

            /**   NSJSONReadingOptions
             *    NSJSONReadingMutableContainers  = (1UL << 0),
             *    容器可變,NSMutableDictionary 或NSMutableArray。
             *
             *    NSJSONReadingMutableLeaves      = (1UL << 1),
             *    葉子可變,返回的 JSON 對象中字符串的值爲 NSMutableString。
             *
             *    NSJSONReadingAllowFragments     = (1UL << 2)
             *    容許 JSON 字符串最外層既不是 NSArray 也不是 NSDictionary,但必須是有效的 JSON 片斷
             */

            //JSON(字典)轉模型
            NSDictionary *dic =  [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            //取將來7每天氣
            NSArray *future = dic[@"result"][@"future"];
            for(int i = 0; i < future.count; i++){

                NSDictionary *wd = future[i];
                // 此處建立Weather還有優化空間,詳情請見下一節 使用KVC的方式優化json轉換Model
                Weather *w = [[Weather alloc]init];

                w.temperature = wd[@"temperature"];
                w.weather = wd[@"weather"];
                w.wind = wd[@"wind"];
                w.week = wd[@"week"];
                w.date_y = wd[@"date"];

                [self.weathers addObject:w];

            }

            NSLog(@"%ld", self.weathers.count);

            //默認網絡請求在自線程 更新界面要回到主線程
            dispatch_async(dispatch_get_main_queue(), ^{
                // 模擬加載數據2s,加一點進度條;現實狀況是不須要的
                [NSThread  sleepForTimeInterval:2.0];

                //刷新界面
                [self.weatherTableView reloadData];

                [self.indicator stopAnimating];

            });

        }

    }];

    //5.開啓任務
    [task resume];

}
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    WeatherCell *cell = [tableView dequeueReusableCellWithIdentifier:@"weather"];
    cell.w = self.weathers[indexPath.row];
    return cell;
}

- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return  self.weathers.count;
}
@end

複製代碼

上面的代碼展現瞭如何請求網絡並展現列表,列表如何展現詳情請見:iOS 開發-非徹底指南之: TableView 的使用詳解json

4. 使用 KVC 的方式優化 json 轉換 Model(優化)

此處的案例是基於上面的 json 請求;前面再獲取到 json 數據轉換成 NSDictonaray,須要本身手動的建立 Weather 並讀取 Key 賦值,在真實的場景下很容易將字段的 key 值寫錯,因此咱們須要使用到 KVC 的方式賦值。後端

優化前的代碼bash

for(int i = 0; i < future.count; i++){
    NSDictionary *wd = future[i];
    Weather *w = [[Weather alloc]init];
    w.temperature = wd[@"temperature"];
    w.weather = wd[@"weather"];
    w.wind = wd[@"wind"];
    w.week = wd[@"week"];
    w.date_y = wd[@"date"];
    [self.weathers addObject:w];
}

複製代碼

優化後的代碼

for(int i = 0; i < future.count; i++){
    NSDictionary *wd = future[i];
    Weather *w = [[Weather alloc] initWithDictionary:wd];
    [self.weathers addObject:w];
}
複製代碼

須要在 Weath 中構造一個initWithDictionary初始化函數:

//
//  Weather.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Weather : NSObject

@property (nonatomic, copy) NSString * temperature;
@property (nonatomic, copy) NSString * weather;
@property (nonatomic, copy) NSString * wind;
@property (nonatomic, copy) NSString * week;
@property (nonatomic, copy) NSString * date_y;
- (instancetype)initWithDictionary:(NSDictionary *) dic; // 新增的

@end

NS_ASSUME_NONNULL_END

複製代碼

而後在 Weather.m 中實現其函數

//
//  Weather.m
#import "Weather.h"

@implementation Weather

-(instancetype)initWithDictionary:(NSDictionary *)dic {

    if (self = [super init]) {
        // 使用KVC的方式給屬性賦值,直接將key給Model中的key
        [self setValuesForKeysWithDictionary:dic];
    }

    return self;
}


//屬性與字典不匹配時進行改正,不改的話不會崩潰但拿不到值
- (void)setValue:(id)value forKey:(NSString *)key{
    //在這裏更改key
    if([key isEqualToString:@"date"]){

        key = @"date_y";
    }

    [super setValue:value forKey:key];
}

//冗錯處理,若是有未定義的字段的話就會走到這裏,不重寫的話會引發崩潰
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{

    NSLog(@"value:%@,undefineKey:%@",value,key);
}
@end

複製代碼

總結:

  • 可使用setValuesForKeysWithDictionary將字典中的 key 和 value 映射到咱們的 Model 中;
  • setValuesForKeysWithDictionary使用前提是返回的 json 和 Model 的屬性相同/相似的狀況;
  • 在映射的過程當中必須處理字段不一樣setValue,forKey以及不須要的字段 forUndefinedKey
  • 當服務器返回的字段爲 iOS 中的關鍵字也須要使用setValue,forKey進行轉換
  • 使用 KVC 的方式可以更好的封裝 dic to model 的轉換;避免在代碼中直接的獲取和賦值

5. 發送 POST 請求

發送 POST 網絡請求,主要流程和 GET 請求相似,主要差別在構建NSURLRequest的部分;一個簡單的例子以下:

//1.建立可變的請求對象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

//2.修改請求方法爲POST
request.HTTPMethod = @"POST";

//4.設置請求體信息,字符串--->NSData
request.HTTPBody = [@"username=mrgaogang&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];

複製代碼

6. 原生文件下載

寫在前面: 建議使用 AFNetworking 的文件下載

使用原生的方式實現文件下載主要有以下幾個步驟:

  1. 肯定須要下載的文件 url
  2. 建立去請求對象
  3. 使用sessionWithConfiguration建立 Session 對象,並設置請求代理NSURLSessionTaskDelegate和隊列
    • 實現代理方法監聽下載進度: downloadTask bytesWritten totalBytesWritten
    • 實現代理方法實現下載完成存儲: downloadTask didFinishDownloadingToURL
  4. 使用downloadTaskWithRequest下載文件
  5. 啓動 Task

一個簡單的例子:

#import "ViewController.h"
@interface ViewController () <NSURLSessionDownloadDelegate>

@property (weak, nonatomic) IBOutlet UIProgressView *downloadProgress;

@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    // 1.肯定URL
    NSURL *url = [NSURL URLWithString:@"http://localhost:8080/AppTestAPI/wall.png"];

    // 2.建立請求對象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 3.建立會話對象
    //NSURLSession *session = [NSURLSession sharedSession];

    // Configuration:配置信息,用默認的便可;將下載的代理方法設置爲self並設置爲主隊列
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];

    [downloadTask resume];// 執行Task
}


/**
 1.寫數據(監聽下載進度)
 session 會話對象
 downloadTask 下載任務
 bytesWritten 本次寫入的數據大小
 totalBytesWritten 下載的數據總大小
 totalBytesExpectedToWrite 文件的總大小
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    self.downloadProgress.progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
}


/**
 3.當下載完成的時候調用
 location 文件的臨時存儲路徑,在沙盒中的tmp目錄下
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    // 1.拼接文件全路徑
    // downloadTask.response.suggestedFilename 文件名稱
    NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
    // 2.剪切文件
    [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
    NSLog(@"%@",fullPath);
}

@end

複製代碼

7. 原生的文件上傳

寫在前面:建議使用 AFNetworking 的文件上傳功能

原生的文件上傳功能比較複雜,主要分爲以下幾個步驟:

    1. 設置上傳的 url
    1. 建立請求對象
    • 設置請求頭 Content-Type
    • 設置請求方法爲 POST , 通常上傳走的是 post 請求
    1. 建立請求 Session 代理, NSURLSessionTaskDelegate並實現以下方法
    • 監聽上傳進度: task didSendBodyData totalBytesSent
    • 監聽是否上傳完成: task didCompleteWithError
    1. 建立上傳 Task: uploadTaskWithRequest
    • 並封裝上傳數據 fromData 包括啓動標記,文件參數和結束標記
    1. 啓動 Task

一個簡單的例子:

#import "ViewController.h"
@interface ViewController ()<NSURLSessionTaskDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    NSURL *url = [NSURL URLWithString:@"上傳的url"];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];

    NSString *httpHead = [NSString stringWithFormat:@"multipart/form-data;boundary=----WebKitFormBoundaryUFNaH6losNxu4xDq"];

    //設置請求的頭 告訴服務器我要上傳數據
    [request setValue:httpHead forHTTPHeaderField:@"Content-Type"];

    request.HTTPMethod = @"POST";

    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];


    //fromData:就是要上傳的數據
    NSURLSessionUploadTask *task =  [session uploadTaskWithRequest:request fromData:[self getData] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        NSLog(@"%@", [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);

    }];


    [task resume];

}

-(NSData *)getData
{
    /******************************************************************/
    //                          設置請求體
    // 設置請求體
    // 給請求體加入固定格式數據  這裏也是使用的也是可變的,由於多嘛
    NSMutableData *data = [NSMutableData data];

    //                       開始標記
    // boundary
    [data appendData:[@"------WebKitFormBoundaryUFNaH6losNxu4xDq" dataUsingEncoding:NSUTF8StringEncoding]];
    // \r\n換行符
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // Content-Disposition: form-data; name="myfile"; filename="wall.jpg"
    [data appendData:[@"Content-Disposition: form-data; name=\"myfile\"; filename=\"123.jpg\"" dataUsingEncoding:NSUTF8StringEncoding]];
    // \r\n換行符
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // Content-Type 上傳文件的MIME
    [data appendData:[@"Content-Type: image/jpeg" dataUsingEncoding:NSUTF8StringEncoding]];
    // 兩個換行符
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];



    //                      上傳文件參數
    //圖片數據  而且轉換爲Data
    UIImage *image = [UIImage imageNamed:@"wall.jpg"];
    NSData *imagedata = UIImageJPEGRepresentation(image, 1.0);
    [data appendData:imagedata];

    //若是是PNG圖片須要修改上面幾個地方 數據格式以下
//    UIImage *image2 = [UIImage imageNamed:@"wall2"];
//    NSData *imagedata2 = UIImagePNGRepresentation(image2);
//    [data appendData:imagedata2];
//

    //若是上傳的是zip壓縮包
    //NSString *path = [[NSBundle mainBundle] pathForResource:@"wall.zip" ofType:nil];
    //[data appendData:[NSData dataWithContentsOfFile:path]];


    // 兩個換行符
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];



    //                      添加結束標記

    // \r\n換行符
    [data appendData:[@"------WebKitFormBoundaryUFNaH6losNxu4xDq--" dataUsingEncoding:NSUTF8StringEncoding]];
    // boundary
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];


    return data;

}

/*
 只要給服務器上傳數據就會調用 (一次或屢次)
 bytesSent: 當前這一次發送的數據長度
 totalBytesSent: 總共已經發送的數據長度
 totalBytesExpectedToSend: 須要上傳的文件的總大小
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
    NSLog(@"%lld", 100 * totalBytesSent / totalBytesExpectedToSend);
}

/*
 判斷是否上傳成功,若是失敗error是具備值
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"%s, %@", __func__, error);
}


@end
複製代碼

2、常見第三方庫使用

1. AFNetworking 的使用

git 地址: AFNetworking

普通網絡請求

AFNetworking 的使用相比原生請求主要有以下差別:

  • 使用了NSURLSessionConfiguration並自定義了 NSURLSession
  • 使用AFURLSessionManager封裝了文件上傳,下載及斷點續傳和普通的網絡請求
  • 對於普通網絡請求直接返回響應後轉換的數據 responseObject; 無需本身經過 NSData 轉換成 JSON
  • 無需手動回到主線程執行 UI 更新操做
-(void)weather{
    //建立管理者
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    //建立網絡請求
    NSString *net = @"http://v.juhe.cn/weather/index?format=2&cityname=重慶&key=2d2e6e836dbdffac56814bc4d449d507";
    net = [net stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *URL = [NSURL URLWithString:net];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    //建立任務
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request uploadProgress:^(NSProgress * _Nonnull uploadProgress) {
    } downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (error) {
            NSLog(@"Error: %@", error);
        } else {
            //須要轉換成NSHTTPURLResponse
            NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
            NSLog(@"%ld", (long)res.statusCode);
            NSLog(@"%@ %@", response, responseObject);
            // 網絡請求直接返回響應後轉換的數據responseObject,無需本身手動轉換
            //取將來7每天氣
            NSArray *future = responseObject[@"result"][@"future"];
            for(int i = 0; i < future.count; i++){
                NSDictionary *wd = future[i];
                Weather *w = [[Weather alloc]initWithDictionary:wd];
                [self.weathers addObject:w];
            }
            //刷新界面,無需回到主線程
            [self.weatherTableView reloadData];
            [self.indicator stopAnimating];
        }
    }];

    //啓動任務
    [dataTask resume];

}

複製代碼

文件上傳

注意點:

  • 主要使用uploadTaskWithRequest完成上傳可使用 process 監聽上傳進度
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];

NSURL *filePath = [NSURL fileURLWithPath:@"file://path/to/image.png"];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
    if (error) {
        NSLog(@"Error: %@", error);
    } else {
        NSLog(@"Success: %@ %@", response, responseObject);
    }
}];
[uploadTask resume];
複製代碼

文件下載

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL *URL = [NSURL URLWithString:@"https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2529366712,3648628205&fm=26&gp=0.jpg"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];

NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {

    // 此處將文件存儲在沙盒中的Document中名稱就使用建議的名稱,也就是文件默認的名稱
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];

    // 或者使用NSSearchPathForDirectoriesInDomains的方式
    // NSString *documentsDirectoryURL = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    // NSString *fileUrl = [documentsDirectoryURL stringByAppendingPathComponent:response.suggestedFilename];
    // NSURL *url = [NSURL fileURLWithPath:fileUrl]; // 注意此處必須是fileURLWithPath
    // 此處將文件存儲在沙盒中的Document中名稱就使用建議的名稱,也就是文件默認的名稱
    // return url;

} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    NSLog(@"File downloaded to: %@", filePath);
}];
[downloadTask resume];
複製代碼

請求參數序列化

請求支持 NSDictionary 不須要再使用?拼接;也支持 POST 請求 HTTPBody

NSString *URLString = @"http://example.com";
NSDictionary *parameters = @{@"foo": @"bar", @"baz": @[@1, @2, @3]};

複製代碼

JSON 類型

[[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters error:nil];

複製代碼
POST http://example.com/
Content-Type: application/json

{"foo": "bar", "baz": [1,2,3]}
複製代碼

query 參數類型

[[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:parameters error:nil];
複製代碼
GET http://example.com?foo=bar&baz[]=1&baz[]=2&baz[]=3
複製代碼

表單類型

[[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:URLString parameters:parameters error:nil];
複製代碼
POST http://example.com/
Content-Type: application/x-www-form-urlencoded

foo=bar&baz[]=1&baz[]=2&baz[]=3
複製代碼

檢測網絡狀態(Network Reachability Manager)

[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusNotReachable: //沒網絡

                break;
            case AFNetworkReachabilityStatusReachableViaWiFi://WIFI代碼

                break;
            case AFNetworkReachabilityStatusReachableViaWWAN: //蜂窩移動數據

                break;

            default:
                break;
        }
    }];

[[AFNetworkReachabilityManager sharedManager] startMonitoring];

複製代碼

網絡狀態 status 有:

  • AFNetworkReachabilityStatusNotReachable : 沒網絡
  • AFNetworkReachabilityStatusReachableViaWWAN: 蜂窩移動數據
  • AFNetworkReachabilityStatusReachableViaWiFi: WiFi
  • AFNetworkReachabilityStatusUnknown: 未知網絡

2. SDWebImage 的使用

SDWebImage 是一個 iOS 端的圖片加載庫。

git 地址: SDWebImage

基礎使用

#import "SDWebImage/UIImageView+WebCache.h"

//經過SDWebImage加載圖片
NSURL *url = [NSURL URLWithString:@"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1571140150,993479906&fm=26&gp=0.jpg"];

[self.icon sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"rain"]];

複製代碼

Gift 圖片

SDAnimatedImageView *imageView = [SDAnimatedImageView new];
SDAnimatedImage *animatedImage = [SDAnimatedImage imageNamed:@"image.gif"];
imageView.image = animatedImage;

複製代碼

3. 下拉刷新 MJRefresh

git 地址: MJRefresh

MJRefresh 實在是太強大了,不只僅是下拉刷新,還有上拉加載,指定位置刷新等,建議看官方文檔

參考

相關文章
相關標籤/搜索