美文网首页
多线程网络04

多线程网络04

作者: 努力爬行中的蜗牛 | 来源:发表于2019-12-13 16:00 被阅读0次
1 GCD中的定时器

1.1 CFRunLoopTimerRef

  • CFRunLoopTimerRef是基于时间的触发器
  • 基本上说的就是NSTimer

1.2 GCD中的定时器
GCD中的定时器不受runloop模式影响

- (void)gcdTimer {
    //1 创建GCD的定时器
    /*
     参数1:source类型 DISPATCH_SOURCE_TYPE_TIMER  定时器
     参数2:描述信息 如线程ID
     参数3:更详细的描述信息
     参数4:队列,决定GCD的定时器在哪个线程中执行
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    //2 设置定时器(起始时间|间隔时间|精准度)
    /*
    参数1:定时器
    参数2:起始时间 DISPATCH_TIME_NOW 从现在开始计时
    参数3:间隔时间 GCD中时间的单位是纳秒
    参数4:精准度,绝对精准
    */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    //3 设置定时器执行的任务
    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

  • 现在的分法
    1)Source0:非基于Port的
    2)Source1:基于Port的

Snip20191213_1.png
3 CFRunLoopObserverRef简单介绍

3.1 CFRunLoopObserverRef

  • CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变
  • 可以监听的时间点有以下几个
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0), // 即将进入RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7), // 即将退出RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU // 所有状态
};

3.2 监听RunLoop示例

- (void)observer {
    // 创建监听者
    /*
     参数1:怎么分配存储空间
     参数2:要监听的状态 kCFRunLoopAllActivities 所有状态
     参数3:是否持续监听
     参数4:优先级,总是传0
     参数5:当前状态改变时回调
     */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        /*
         typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
             kCFRunLoopEntry = (1UL << 0), // 即将进入RunLoop
             kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
             kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source
             kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
             kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
             kCFRunLoopExit = (1UL << 7), // 即将退出RunLoop
             kCFRunLoopAllActivities = 0x0FFFFFFFU // 所有状态
         };
         */
        switch (activity) {
            case kCFRunLoopEntry:
                NSLog(@"即将进入RunLoop");
                break;
            case kCFRunLoopBeforeTimers:
                NSLog(@"即将处理Timer事件");
                break;
            case kCFRunLoopBeforeSources:
                NSLog(@"即将处理Source事件");
                break;
            case kCFRunLoopBeforeWaiting:
                NSLog(@"即将进入休眠");
                break;
            case kCFRunLoopAfterWaiting:
                NSLog(@"刚从休眠中唤醒");
                break;
            case kCFRunLoopExit:
                NSLog(@"即将退出RunLoop");
                break;
                
            default:
                break;
        }
    });
    /*
     参数1:要监听那个runloop
     参数2:观察者
     参数3:runloop运行模式
     */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
}
4 CFRunLoop运行流程

4.1 RunLoop处理逻辑


runloop内部.png 处理逻辑-网络版.png 处理逻辑-官方版.png
5 RunLoop应用

5.1 常见应用

  • 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];
    // 默认是没有开启的,需要开启
    [currentLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    
}

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

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

5.3 自动释放池

  • 第一次创建:在启动runloop的时候
  • 最后一次销毁:runloop退出的时候
  • 其他时候的创建和销毁:当runloop即将睡眠的时候销毁之前创建的释放池,重新创建一个新的。
6 网络基本概念

6.1 几个基本概念

  • 客户端:移动应用
  • 服务端:为客户端提供服务、提供数据、提供资源的机器
  • 请求:客户端向服务器索取数据的一种行为
  • 响应:服务器对客户端请求作出的响应,一般指返回数据给客户端

6.2 服务器
按照软件开发来分,服务器可以大致分为2种:

  • 远程服务器
  • 本地服务器
7 HTTP协议简单介绍

7.1 URL

  • 全称是Uniform Resource Locator(统一资源定位符)
  • 通过1个URL,能找到互联网上唯一的1一个资源
  • URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL
  • URL的基本格式 = 协议://主机地址/路径
    1)协议:不同的协议,达标不同的资源查找方式,资源传输方式
    2)主机地址:存放资源的主机(服务器)的IP地址(域名)
    3)路径:资源在主机(服务器)中的具体位置

7.2 URL中的常见协议

  • HTTP
    超文本传输协议,访问的是远程的网络资源,格式是http://
    http协议是在网络开发中最常见的协议
  • file
    访问的是本地计算机的资源,格式是file:// (不用加主机地址)
  • mailto
    访问的是电子邮件地址,格式是mailto:
  • FTP
    访问的是共享主机的文件资源,格式是ftp://

7.3 HTTP协议特点

  • 简单快速
  • 因为HTTP协议简单,所以HTTP服务器的程序规模小,因而通信速度很快
  • 灵活
    HTTP允许传输各种各样的数据
  • HTTP0.9和1.0使用非持续连续
    限制每次连接只处理一个请求,服务器对客户端的请求作出响应,马上断开连接,这种方式可以节省传输时间
8 GET请求和POST请求

8.1 发送HTTP请求的方法
在HTTP/1.1协议中,定义了8种http请求的方法
GET、POST、OPTIONS、HEAD、PUT、DELETE、TARCE、CONNECT、PATCH

  • 根据HTTP协议的设计初衷,不同的方法对资源有不同操作方式
    1)PUT:增
    2)DELETE:删
    3)POST:改
    4)GET:查
    最常用的是GET和POST(实际上GET和POST都能办到增删改查)

8.2 GET和POST的对比

  • GET
    在请求URL后面以?的形式跟上发给服务器的参数,多个参数之间用&隔开,比如 http://ww.test.com/login?username=123&pwd=234&type=JSON
    由于浏览器和服务器对URL长度有限制,因此在URL后面附带的参数是有限制的,通常不能超过1KB

  • POST
    发给服务器的参数全部放在请求体中
    理论上,POST传递的数据量没有限制(具体还得看服务器的处理能力)

  • 如何选择【除简单数据查询外,其它的一律使用POST请求】
    a.如果要传递大量数据,比如文件上传,只能用POST请求
    b.GET的安全性比POST要差些,如果包含机密\敏感信息,建议用POST
    c.如果仅仅是索取数据(数据查询),建议使用GET
    d.如果是增加、修改、删除数据,建议使用POST

9 HTTP通信过程

9.1 请求
HTTP协议规定:1个完整的有客户端发送给服务器的HTTP请求包含以下内容

  • 请求头:包含了对客户端的环境描述、客户端请求信息等
  • 请求体:客户端发送给服务器的具体数据,比如文件数据(POST请求才会有)

9.2 响应
客户端向服务器发送请求,服务器应当作出响应,即返回数据给客户端

  • HTTP协议规定:1个完整的HTTP响应包含以下内容:...
  • 响应体:服务器返回给客户端的具体数据,比如文件数据

9.3 常见响应状态

状态码 英文名称 中文描述
200 ok 请求成功
400 Bad Request 客户端请求的语法错误,服务器无法解析
404 Not found 服务器无法根据客户端的请求找到资源
500 Internal Server Error 服务器内部错误,无法完成请求

9.4 iOS中发送HTTP请求的方案
在iOS中,常见的发送HTTP请求的方案有

  • 苹果原生(自带)
    1)NSURLConnection:用法简单,最古老最经典最直接的一种方案【坑比较多】
    2)NSURLSession:功能比NSURLConnection更加强大,苹果目前比较推荐使用这种技术【2013年推出,iOS7开始出的技术】
    3)CFNetwork:NSRUL的底层,纯c语言

  • 第三方框架
    1)ASIHttpRequest:外号“HTTP终结者”,功能强大,但早已停止更新
    2)AFNetworking:简单易用,提供了基本够用的常用功能,维护和使用者较多
    3)MKNetworkKit:简单易用,产自三哥的故乡印度,维护和使用者较少

10 NSURLConnection

10.1 作用

  • 负责发送请求,建立客户端和服务器的链接
  • 发送数据给服务器,并收集来自服务器的响应数据

10.2 使用步骤

  • 创建一个NSURL对象,设置请求路径
  • 传入NSURL,创建一个NSURLRequest对象,设置请求头和请求体
  • 使用NSURLConnection发送请求

10.3 发送同步和异步GET请求
默认为GET请求

// 同步请求
- (void)sync {
    //1 url地址
    //
    NSURL *url = [NSURL URLWithString:@"https://static.guxiansheng.cn/hq_info.json"];
    //2 请求请求对象
    // 请求头不需要设置(默认请求头)
    NSURLRequest *requet = [NSURLRequest requestWithURL:url];
    //3 发送同步请求
    /*
     参数1:请求对象
     参数2:响应头
     参数3:错误信息
     参数4:响应体
     */
    NSHTTPURLResponse *res = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:requet returningResponse:&res error:nil];
    //4 解析数据
    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 请求请求对象
    // 请求头不需要设置(默认请求头)
    NSURLRequest *requet = [NSURLRequest requestWithURL:url];
    //3 发送异步请求
    /*
     参数1:请求对象
     参数2:队列,决定代码块的调用线程
     参数3:completionHandler 请求完成的时候调用
     response:响应头
     data:响应体
     connectionError:错误信息
     */
    [NSURLConnection sendAsynchronousRequest:requet queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4 解析数据
        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 请求请求对象
    // 请求头不需要设置(默认请求头)
    NSURLRequest *requet = [NSURLRequest requestWithURL:url];
    //3 发送异步请求
    // 方式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 客户端收到服务端响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"%s",__func__);
}
//2 客户端接收到服务端数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.recieveData appendData:data];
}
//3 客户端数据请求失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%s",__func__);
}
//4 客户度数据请求完毕
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //4 解析数据
    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发送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];
    // 设置请求方法 POST必须大写
    requet.HTTPMethod = @"POST";
    // 设置请求头信息
    [requet setValue:@"ios10.2" forHTTPHeaderField:@"User-Agent"];
    // 设置超时时间
    requet.timeoutInterval = 10;
    //3 设置请求体
    NSString *requtstBody = @"id=1&appcode=5c6bb51a113c8szji5nb6cur";
    requet.HTTPBody = [requtstBody dataUsingEncoding:NSUTF8StringEncoding];
    //4 发送请求
    [NSURLConnection sendAsynchronousRequest:requet queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4 解析数据
        NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@",strData);
        NSURLResponse *res = (NSURLResponse *)response;
        NSLog(@"%@",res);
    }];
}
11 URL中文转码

是否需要转码主要看url里面是否存在中文,请求体里面的中文是不需要做转码处理的。

- (void)demo {
    NSString *strUrl = @"https://static.guxiansheng.cn/hq_info.json?v=哈哈";
    NSLog(@"%@",strUrl);
    // 中文转码
    //strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    strUrl = [strUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSLog(@"%@",strUrl);
    NSURL *url = [NSURL URLWithString:strUrl];
    NSLog(@"%@",url);
}
12 JSON解析简单介绍

12.1 什么是JSON

  • JSON是一种轻量级的数据格式,一般用于数据交互
  • 服务器传给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外)
  • JSON的格式很像OC中的字典和数组
    {"name" : "jack", "age" : 10}
    {"name" : ["jack" ,"rose", "jie"]}
  • 标砖JSON格式的注意点:key必须用双引号
  • 要想从JSON中挖掘出具体数据,得对JSON进行解析

12.1 JSON - OC 转换对照表

JSON OC
大括号{} NSDictionary
中括号[] NSArray
双引号"" NSString
数字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;

相关文章

网友评论

      本文标题:多线程网络04

      本文链接:https://www.haomeiwen.com/subject/zaaxnctx.html