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的

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处理逻辑



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;
网友评论