多線程網(wǎng)絡(luò)04

1 GCD中的定時器

1.1 CFRunLoopTimerRef

  • CFRunLoopTimerRef是基于時間的觸發(fā)器
  • 基本上說的就是NSTimer

1.2 GCD中的定時器
GCD中的定時器不受runloop模式影響

- (void)gcdTimer {
    //1 創(chuàng)建GCD的定時器
    /*
     參數(shù)1:source類型 DISPATCH_SOURCE_TYPE_TIMER  定時器
     參數(shù)2:描述信息 如線程ID
     參數(shù)3:更詳細(xì)的描述信息
     參數(shù)4:隊(duì)列,決定GCD的定時器在哪個線程中執(zhí)行
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    //2 設(shè)置定時器(起始時間|間隔時間|精準(zhǔn)度)
    /*
    參數(shù)1:定時器
    參數(shù)2:起始時間 DISPATCH_TIME_NOW 從現(xiàn)在開始計時
    參數(shù)3:間隔時間 GCD中時間的單位是納秒
    參數(shù)4:精準(zhǔn)度,絕對精準(zhǔn)
    */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    //3 設(shè)置定時器執(zhí)行的任務(wù)
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
    //4 啟動定時器
    dispatch_resume(timer);
    self.timer = timer;
}
2 CFRunLoopSourceRef簡單介紹

2.1 CFRunLoopSourceRef是事件源(輸入源)

  • 以前的分法
    1)Port-Based Sources
    2)Custom Input Source
    3)Cocoa Perform Selector Source

  • 現(xiàn)在的分法
    1)Source0:非基于Port的
    2)Source1:基于Port的

Snip20191213_1.png
3 CFRunLoopObserverRef簡單介紹

3.1 CFRunLoopObserverRef

  • CFRunLoopObserverRef是觀察者,能夠監(jiān)聽RunLoop的狀態(tài)改變
  • 可以監(jiān)聽的時間點(diǎn)有以下幾個
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即將處理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒
    kCFRunLoopExit = (1UL << 7), // 即將退出RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU // 所有狀態(tài)
};

3.2 監(jiān)聽RunLoop示例

- (void)observer {
    // 創(chuàng)建監(jiān)聽者
    /*
     參數(shù)1:怎么分配存儲空間
     參數(shù)2:要監(jiān)聽的狀態(tài) kCFRunLoopAllActivities 所有狀態(tài)
     參數(shù)3:是否持續(xù)監(jiān)聽
     參數(shù)4:優(yōu)先級,總是傳0
     參數(shù)5:當(dāng)前狀態(tài)改變時回調(diào)
     */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        /*
         typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
             kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入RunLoop
             kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理Timer
             kCFRunLoopBeforeSources = (1UL << 2), // 即將處理Source
             kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
             kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠中喚醒
             kCFRunLoopExit = (1UL << 7), // 即將退出RunLoop
             kCFRunLoopAllActivities = 0x0FFFFFFFU // 所有狀態(tài)
         };
         */
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"即將進(jìn)入RunLoop");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即將處理Timer事件");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即將處理Source事件");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即將進(jìn)入休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"剛從休眠中喚醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"即將退出RunLoop");
                break;
                
            default:
                break;
        }
    });
    /*
     參數(shù)1:要監(jiān)聽那個runloop
     參數(shù)2:觀察者
     參數(shù)3:runloop運(yùn)行模式
     */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
}
4 CFRunLoop運(yùn)行流程

4.1 RunLoop處理邏輯


runloop內(nèi)部.png
處理邏輯-網(wǎng)絡(luò)版.png
處理邏輯-官方版.png
5 RunLoop應(yīng)用

5.1 常見應(yīng)用

  • NSTimer
  • ImageView顯示
  • PerformSelector
  • 常駐線程
  • 自動釋放池

5.2 常駐線程demo

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(task1) object:nil];
    [self.thread start];
}


- (IBAction)btnClicked:(id)sender {
    [self performSelector:@selector(task2) onThread:self.thread withObject:nil waitUntilDone:YES];
}

- (void)task1 {
    NSLog(@"task1---%@",[NSThread currentThread]);
    // 讓線程常駐不退出的解決方案:開runloop
    //1 獲取子線程的runloop
    NSRunLoop *currentLoop = [NSRunLoop currentRunLoop];
    // 保證runloop不退出: 添加timer或者source
    //NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
    //[currentLoop addTimer:timer forMode:NSDefaultRunLoopMode];
    [currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    // 默認(rèn)是沒有開啟的,需要開啟
    [currentLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    
}

- (void)task2 {
    NSLog(@"task2---%@",[NSThread currentThread]);
}

- (void)run {
    NSLog(@"%s",__func__);
}

5.3 自動釋放池

  • 第一次創(chuàng)建:在啟動runloop的時候
  • 最后一次銷毀:runloop退出的時候
  • 其他時候的創(chuàng)建和銷毀:當(dāng)runloop即將睡眠的時候銷毀之前創(chuàng)建的釋放池,重新創(chuàng)建一個新的。
6 網(wǎng)絡(luò)基本概念

6.1 幾個基本概念

  • 客戶端:移動應(yīng)用
  • 服務(wù)端:為客戶端提供服務(wù)、提供數(shù)據(jù)、提供資源的機(jī)器
  • 請求:客戶端向服務(wù)器索取數(shù)據(jù)的一種行為
  • 響應(yīng):服務(wù)器對客戶端請求作出的響應(yīng),一般指返回數(shù)據(jù)給客戶端

6.2 服務(wù)器
按照軟件開發(fā)來分,服務(wù)器可以大致分為2種:

  • 遠(yuǎn)程服務(wù)器
  • 本地服務(wù)器
7 HTTP協(xié)議簡單介紹

7.1 URL

  • 全稱是Uniform Resource Locator(統(tǒng)一資源定位符)
  • 通過1個URL,能找到互聯(lián)網(wǎng)上唯一的1一個資源
  • URL就是資源的地址、位置,互聯(lián)網(wǎng)上的每個資源都有一個唯一的URL
  • URL的基本格式 = 協(xié)議://主機(jī)地址/路徑
    1)協(xié)議:不同的協(xié)議,達(dá)標(biāo)不同的資源查找方式,資源傳輸方式
    2)主機(jī)地址:存放資源的主機(jī)(服務(wù)器)的IP地址(域名)
    3)路徑:資源在主機(jī)(服務(wù)器)中的具體位置

7.2 URL中的常見協(xié)議

  • HTTP
    超文本傳輸協(xié)議,訪問的是遠(yuǎn)程的網(wǎng)絡(luò)資源,格式是http://
    http協(xié)議是在網(wǎng)絡(luò)開發(fā)中最常見的協(xié)議
  • file
    訪問的是本地計算機(jī)的資源,格式是file:// (不用加主機(jī)地址)
  • mailto
    訪問的是電子郵件地址,格式是mailto:
  • FTP
    訪問的是共享主機(jī)的文件資源,格式是ftp://

7.3 HTTP協(xié)議特點(diǎn)

  • 簡單快速
  • 因?yàn)镠TTP協(xié)議簡單,所以HTTP服務(wù)器的程序規(guī)模小,因而通信速度很快
  • 靈活
    HTTP允許傳輸各種各樣的數(shù)據(jù)
  • HTTP0.9和1.0使用非持續(xù)連續(xù)
    限制每次連接只處理一個請求,服務(wù)器對客戶端的請求作出響應(yīng),馬上斷開連接,這種方式可以節(jié)省傳輸時間
8 GET請求和POST請求

8.1 發(fā)送HTTP請求的方法
在HTTP/1.1協(xié)議中,定義了8種http請求的方法
GET、POST、OPTIONS、HEAD、PUT、DELETE、TARCE、CONNECT、PATCH

  • 根據(jù)HTTP協(xié)議的設(shè)計初衷,不同的方法對資源有不同操作方式
    1)PUT:增
    2)DELETE:刪
    3)POST:改
    4)GET:查
    最常用的是GET和POST(實(shí)際上GET和POST都能辦到增刪改查)

8.2 GET和POST的對比

  • GET
    在請求URL后面以?的形式跟上發(fā)給服務(wù)器的參數(shù),多個參數(shù)之間用&隔開,比如 http://ww.test.com/login?username=123&pwd=234&type=JSON
    由于瀏覽器和服務(wù)器對URL長度有限制,因此在URL后面附帶的參數(shù)是有限制的,通常不能超過1KB

  • POST
    發(fā)給服務(wù)器的參數(shù)全部放在請求體中
    理論上,POST傳遞的數(shù)據(jù)量沒有限制(具體還得看服務(wù)器的處理能力)

  • 如何選擇【除簡單數(shù)據(jù)查詢外,其它的一律使用POST請求】
    a.如果要傳遞大量數(shù)據(jù),比如文件上傳,只能用POST請求
    b.GET的安全性比POST要差些,如果包含機(jī)密\敏感信息,建議用POST
    c.如果僅僅是索取數(shù)據(jù)(數(shù)據(jù)查詢),建議使用GET
    d.如果是增加、修改、刪除數(shù)據(jù),建議使用POST

9 HTTP通信過程

9.1 請求
HTTP協(xié)議規(guī)定:1個完整的有客戶端發(fā)送給服務(wù)器的HTTP請求包含以下內(nèi)容

  • 請求頭:包含了對客戶端的環(huán)境描述、客戶端請求信息等
  • 請求體:客戶端發(fā)送給服務(wù)器的具體數(shù)據(jù),比如文件數(shù)據(jù)(POST請求才會有)

9.2 響應(yīng)
客戶端向服務(wù)器發(fā)送請求,服務(wù)器應(yīng)當(dāng)作出響應(yīng),即返回數(shù)據(jù)給客戶端

  • HTTP協(xié)議規(guī)定:1個完整的HTTP響應(yīng)包含以下內(nèi)容:...
  • 響應(yīng)體:服務(wù)器返回給客戶端的具體數(shù)據(jù),比如文件數(shù)據(jù)

9.3 常見響應(yīng)狀態(tài)

狀態(tài)碼 英文名稱 中文描述
200 ok 請求成功
400 Bad Request 客戶端請求的語法錯誤,服務(wù)器無法解析
404 Not found 服務(wù)器無法根據(jù)客戶端的請求找到資源
500 Internal Server Error 服務(wù)器內(nèi)部錯誤,無法完成請求

9.4 iOS中發(fā)送HTTP請求的方案
在iOS中,常見的發(fā)送HTTP請求的方案有

  • 蘋果原生(自帶)
    1)NSURLConnection:用法簡單,最古老最經(jīng)典最直接的一種方案【坑比較多】
    2)NSURLSession:功能比NSURLConnection更加強(qiáng)大,蘋果目前比較推薦使用這種技術(shù)【2013年推出,iOS7開始出的技術(shù)】
    3)CFNetwork:NSRUL的底層,純c語言

  • 第三方框架
    1)ASIHttpRequest:外號“HTTP終結(jié)者”,功能強(qiáng)大,但早已停止更新
    2)AFNetworking:簡單易用,提供了基本夠用的常用功能,維護(hù)和使用者較多
    3)MKNetworkKit:簡單易用,產(chǎn)自三哥的故鄉(xiāng)印度,維護(hù)和使用者較少

10 NSURLConnection

10.1 作用

  • 負(fù)責(zé)發(fā)送請求,建立客戶端和服務(wù)器的鏈接
  • 發(fā)送數(shù)據(jù)給服務(wù)器,并收集來自服務(wù)器的響應(yīng)數(shù)據(jù)

10.2 使用步驟

  • 創(chuàng)建一個NSURL對象,設(shè)置請求路徑
  • 傳入NSURL,創(chuàng)建一個NSURLRequest對象,設(shè)置請求頭和請求體
  • 使用NSURLConnection發(fā)送請求

10.3 發(fā)送同步和異步GET請求
默認(rèn)為GET請求

// 同步請求
- (void)sync {
    //1 url地址
    //
    NSURL *url = [NSURL URLWithString:@"https://static.guxiansheng.cn/hq_info.json"];
    //2 請求請求對象
    // 請求頭不需要設(shè)置(默認(rèn)請求頭)
    NSURLRequest *requet = [NSURLRequest requestWithURL:url];
    //3 發(fā)送同步請求
    /*
     參數(shù)1:請求對象
     參數(shù)2:響應(yīng)頭
     參數(shù)3:錯誤信息
     參數(shù)4:響應(yīng)體
     */
    NSHTTPURLResponse *res = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:requet returningResponse:&res error:nil];
    //4 解析數(shù)據(jù)
    NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",strData);
    NSLog(@"%@",res);
}

// 異步請求,block方式
- (void)async1 {
    //1 url地址
    NSURL *url = [NSURL URLWithString:@"http://gss0.baidu.com/9fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/b3b7d0a20cf431ad39010c0d4d36acaf2edd9837.jpg"];
    //2 請求請求對象
    // 請求頭不需要設(shè)置(默認(rèn)請求頭)
    NSURLRequest *requet = [NSURLRequest requestWithURL:url];
    //3 發(fā)送異步請求
    /*
     參數(shù)1:請求對象
     參數(shù)2:隊(duì)列,決定代碼塊的調(diào)用線程
     參數(shù)3:completionHandler 請求完成的時候調(diào)用
     response:響應(yīng)頭
     data:響應(yīng)體
     connectionError:錯誤信息
     */
    [NSURLConnection sendAsynchronousRequest:requet queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4 解析數(shù)據(jù)
        NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@",strData);
        NSURLResponse *res = (NSURLResponse *)response;
        NSLog(@"%@",res);
    }];
}

//異步請求:代理方式
- (void)async2 {
    //1 url地址
    NSURL *url = [NSURL URLWithString:@"https://static.guxiansheng.cn/hq_info.json"];
    //2 請求請求對象
    // 請求頭不需要設(shè)置(默認(rèn)請求頭)
    NSURLRequest *requet = [NSURLRequest requestWithURL:url];
    //3 發(fā)送異步請求
    // 方式1
    [NSURLConnection connectionWithRequest:requet delegate:self];
    // 方式2
    //[[NSURLConnection alloc] initWithRequest:requet delegate:self];
    // 方式3
    //NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:requet delegate:self startImmediately:YES];
    //[connection start];
    // 取消請求操作
    //[connection cancel];
}

#pragma mark - NSURLConnectionDataDelegate
// 1 客戶端收到服務(wù)端響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"%s",__func__);
}
//2 客戶端接收到服務(wù)端數(shù)據(jù)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.recieveData appendData:data];
}
//3 客戶端數(shù)據(jù)請求失敗
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%s",__func__);
}
//4 客戶度數(shù)據(jù)請求完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //4 解析數(shù)據(jù)
    NSString *strData = [[NSString alloc] initWithData:self.recieveData encoding:NSUTF8StringEncoding];
    NSLog(@"%@",strData);
}

#pragma mark - getter
- (NSMutableData *)recieveData {
    if (!_recieveData) {
        _recieveData = [NSMutableData data];
    }
    return _recieveData;
}

10.4 NSURLConnection發(fā)送POST請求

- (void)post {
    //1 url地址
    NSURL *url = [NSURL URLWithString:@"https://service.agent.guxiansheng.cn?c=adplace&a=getinfoad&v=App&site=marketing"];
    //2 請求請求對象
    NSMutableURLRequest *requet = [NSMutableURLRequest requestWithURL:url];
    // 設(shè)置請求方法 POST必須大寫
    requet.HTTPMethod = @"POST";
    // 設(shè)置請求頭信息
    [requet setValue:@"ios10.2" forHTTPHeaderField:@"User-Agent"];
    // 設(shè)置超時時間
    requet.timeoutInterval = 10;
    //3 設(shè)置請求體
    NSString *requtstBody = @"id=1&appcode=5c6bb51a113c8szji5nb6cur";
    requet.HTTPBody = [requtstBody dataUsingEncoding:NSUTF8StringEncoding];
    //4 發(fā)送請求
    [NSURLConnection sendAsynchronousRequest:requet queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4 解析數(shù)據(jù)
        NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@",strData);
        NSURLResponse *res = (NSURLResponse *)response;
        NSLog(@"%@",res);
    }];
}
11 URL中文轉(zhuǎn)碼

是否需要轉(zhuǎn)碼主要看url里面是否存在中文,請求體里面的中文是不需要做轉(zhuǎn)碼處理的。

- (void)demo {
    NSString *strUrl = @"https://static.guxiansheng.cn/hq_info.json?v=哈哈";
    NSLog(@"%@",strUrl);
    // 中文轉(zhuǎn)碼
    //strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    strUrl = [strUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSLog(@"%@",strUrl);
    NSURL *url = [NSURL URLWithString:strUrl];
    NSLog(@"%@",url);
}
12 JSON解析簡單介紹

12.1 什么是JSON

  • JSON是一種輕量級的數(shù)據(jù)格式,一般用于數(shù)據(jù)交互
  • 服務(wù)器傳給客戶端的數(shù)據(jù),一般都是JSON格式或者XML格式(文件下載除外)
  • JSON的格式很像OC中的字典和數(shù)組
    {"name" : "jack", "age" : 10}
    {"name" : ["jack" ,"rose", "jie"]}
  • 標(biāo)磚JSON格式的注意點(diǎn):key必須用雙引號
  • 要想從JSON中挖掘出具體數(shù)據(jù),得對JSON進(jìn)行解析

12.1 JSON - OC 轉(zhuǎn)換對照表

JSON OC
大括號{} NSDictionary
中括號[] NSArray
雙引號"" NSString
數(shù)字10、10.8 NSNumber

12.2 JSON解析方案

  • 在iOS中,JSON的常見解析方案有4種
  • 第三方框架:JSONkit、SBJson、TouchJson(性能從左到右,越差)
  • 蘋果原生(自帶):NSJSONSerialization(性能最好)
// JSON -> OC  反序列化
+ (nullable id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
// OC -> JSON  序列化
+ (nullable NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • iOS網(wǎng)絡(luò)編程讀書筆記 Facade Tester客戶端門面模式的實(shí)例(被動版本化) 被動版本化,所以硬編碼URL...
    melouverrr閱讀 1,699評論 3 7
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,621評論 1 32
  • 0.第三方框架SDWebImage (1)SDWebImage基本使用 01設(shè)置imageView的圖片 [ce...
    怎樣m閱讀 483評論 0 0
  • Xmind PPT NSOperation RunLoop GitBook 0.第三方框架SDWebImage (...
    CoderZXS閱讀 300評論 0 0
  • 讀了《魅力董》書,書中講了董卿的奮斗歷程、語言魅力、氣質(zhì)修養(yǎng)、情商修煉等各個方面,向讀者展示董卿的個人魅力。從而讓...
    古月飛天閱讀 354評論 0 1

友情鏈接更多精彩內(nèi)容