Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e635651

Browse files
committed
Merge commit 'b5ede8bded597afcb5fb176e514f7889c0f46eeb'
2 parents f9b0a13 + b5ede8b commit e635651

File tree

4 files changed

+156
-77
lines changed

4 files changed

+156
-77
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# BY Blog
22

33
> 下面是博客的搭建教程,这个教程修改自 [Hux](https://github.com/Huxpro/huxpro.github.io)
4-
4+
>
5+
> 更为详细的教程[《利用 GitHub Pages 快速搭建个人博客》](http://www.jianshu.com/p/e68fba58f75c)
6+
>
57
### [我的博客在这里 →](http://qiubaiying.github.io)
68

79
![](https://raw.githubusercontent.com/qiubaiying/qiubaiying.github.io/master/img/readme-home.png)
@@ -31,7 +33,7 @@
3133

3234
### 环境
3335

34-
如果你安装了jekyll,那你只需要在命令行输入`jekyll serve``jekyll s`就能在本地浏览器中输入`http://127.0.0.1:4000/`预览主题,还可以边修改边自动运行修改后的文件(需要刷新浏览器)。
36+
如果你安装了 [jekyll](http://jekyllcn.com/),那你只需要在命令行输入`jekyll serve``jekyll s`就能在本地浏览器中输入`http://127.0.0.1:4000/`预览主题,还可以边修改边自动运行修改后的文件(需要刷新浏览器)。
3537

3638

3739

@@ -58,7 +60,7 @@ Jekyll官方网站还有很多的参数可以调,比如设置文章的链接
5860

5961
### 撰写博文
6062

61-
要发表的文章一般以markdown的格式放在这里`_posts/`,你只要看看这篇模板里的文章你就立刻明白该如何设置。
63+
要发表的文章一般以 **Markdown** 的格式放在这里`_posts/`,你只要看看这篇模板里的文章你就立刻明白该如何设置。
6264

6365
yaml 头文件长这样:
6466

_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ jianshu_username: e71990ada2fd
3030

3131
# Build settings
3232
# from 2016, 'pygments' is unsupported on GitHub Pages. Use 'rouge' for highlighting instead.
33-
highlighter: rouge
3433
permalink: pretty
3534
paginate: 10
3635
exclude: ["less","node_modules","Gruntfile.js","package.json","README.md"]
@@ -49,6 +48,7 @@ gems: [jekyll-paginate]
4948
# although redcarpet can auto highlight code, the lack of header-id make the catalog impossible, so I switch to kramdown
5049
# document: http://jekyllrb.com/docs/configuration/#kramdown
5150
markdown: kramdown
51+
highlighter: rouge
5252
kramdown:
5353
input: GFM # use Github Flavored Markdown !important
5454

_posts/2016-12-13-定时器你真的会使用吗?.md

Lines changed: 54 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,20 @@ tags:
1414

1515
# 前言
1616

17-
定时器的使用是软件开发基础技能,用于延时执行或重复执行某些方法。大部分人接触iOS的定时器都是从
17+
定时器的使用是软件开发基础技能,用于延时执行或重复执行某些方法。
18+
19+
我相信大部分人接触iOS的定时器都是从这段代码开始的:
1820

1921
```objc
2022
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:YES]
2123
```
2224
23-
这段代码开始的吧。
24-
25-
但是关于iOS定时器,你真的会用吗?
25+
但是你真的会用吗?
2626
2727
# 正文
2828
29+
## iOS定时器
30+
2931
首先来介绍iOS中的定时器
3032
3133
iOS中的定时器大致分为这几类:
@@ -37,6 +39,7 @@ iOS中的定时器大致分为这几类:
3739
### NSTimer
3840
3941
#### 使用方法
42+
4043
**NSTime**定时器是我们比较常使用的定时器,比较常使用的方法有两种:
4144
4245
```objc
@@ -46,7 +49,7 @@ iOS中的定时器大致分为这几类:
4649
```
4750
这两种方法都是创建一个定时器,区别是用`timerWithTimeInterval:`方法创建的定时器需要手动加入RunLoop中。
4851

49-
```objc
52+
```
5053
// 创建NSTimer对象
5154
NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
5255
// 加入RunLoop中
@@ -57,7 +60,7 @@ NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector
5760

5861
举个例子:
5962

60-
```objc
63+
```
6164
- (void)startTimer{
6265
NSTimer *UIScrollView = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(action:) userInfo:nil repeats:YES];
6366
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
@@ -74,7 +77,7 @@ NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector
7477

7578
打印台输出:
7679

77-
![](http://ww1.sinaimg.cn/large/006tNc79gw1farbzzwcevj30ci04ljtm.jpg)
80+
![](http://upload-images.jianshu.io/upload_images/2178672-9de097ecc618b498.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
7881

7982
可以看出在滑动`UIScrollView`时,定时器被暂停了。
8083

@@ -83,22 +86,22 @@ NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector
8386

8487
1. **timer**分别添加到 `UITrackingRunLoopMode``NSDefaultRunLoopMode`
8588

86-
```objc
87-
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
88-
[[NSRunLoop mainRunLoop] addTimer:timer forMode: UITrackingRunLoopMode];
89-
```
89+
```objc
90+
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
91+
[[NSRunLoop mainRunLoop] addTimer:timer forMode: UITrackingRunLoopMode];
92+
```
9093
9194
2. 直接将**timer**添加到`NSRunLoopCommonModes` 中:
9295
93-
```objc
94-
[[NSRunLoop mainRunLoop] addTimer:timer forMode: NSRunLoopCommonModes];
95-
```
96+
```objc
97+
[[NSRunLoop mainRunLoop] addTimer:timer forMode: NSRunLoopCommonModes];
98+
```
9699

97100
但并不是都**timer**所有的需要在滑动`UIScrollView`时继续执行,比如使用**NSTimer**完成的帧动画,滑动`UIScrollView`时就可以停止帧动画,保证滑动的流程性。
98101

99-
若没有特殊要求的话,一般使用第二种方法创建完 **timer**,会自动添加到`NSDefaultRunLoopMode` 中去执行,也是平时最常用的方法。
102+
若没有特殊要求的话,一般使用第二种方法创建完**timer**,会自动添加到`NSDefaultRunLoopMode`中去执行,也是平时最常用的方法。
100103

101-
```objc
104+
```
102105
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:) userInfo:nil repeats:YES];
103106
```
104107
参数:
@@ -119,7 +122,7 @@ NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selecto
119122

120123
释放方法:
121124

122-
```objc
125+
```
123126
// 停止定时器
124127
[timer invalidate];
125128
```
@@ -128,13 +131,13 @@ NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selecto
128131

129132
**iOS10.0** 推出了两个新的API,与上面的方法相比,`selector`换成Block回调以、减少传入的参数(那几个参数真是鸡肋)。不过开发中一般需要适配低版本,还是尽量使用上面的方法吧。
130133

131-
```objc
134+
```
132135
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
133136
134137
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
135138
```
136139

137-
#### 特点
140+
###特点
138141

139142
- **必须加入Runloop**
140143

@@ -148,23 +151,23 @@ NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selecto
148151
- **UIScrollView滑动会暂停计时**
149152

150153
添加到`NSDefaultRunLoopMode`的 `timer` 在 `UIScrollView`滑动时会暂停,若不想被`UIScrollView`滑动影响,需要将 `timer` 添加再到 `UITrackingRunLoopMode` 或 直接添加到`NSRunLoopCommonModes` 中
151-
152154

153-
154-
CADisplayLink
155-
---
155+
156+
157+
##CADisplayLink
158+
156159

157160
CADisplayLink官方介绍:
158161
>A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display
159162
160163
**CADisplayLink**对象是一个和屏幕刷新率同步的定时器对象。每当屏幕显示内容刷新结束的时候,runloop就会向CADisplayLink指定的`target`发送一次指定的`selector`消息, CADisplayLink类对应的 `selector` 就会被调用一次。
161164

162165
从原理上可以看出,CADisplayLink适合做界面的不停重绘,比如视频播放的时候需要不停地获取下一帧用于界面渲染,或者做动画。
163-
#### 使用方法
166+
###使用方法
164167

165168
创建:
166169

167-
```objc
170+
```
168171
@property (nonatomic, strong) CADisplayLink *displayLink;
169172
170173
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
@@ -176,7 +179,7 @@ self.displayLink.frameInterval = 1;
176179
```
177180
释放方法:
178181

179-
```objc
182+
```
180183
[self.displayLink invalidate];
181184
182185
self.displayLink = nil;
@@ -194,7 +197,7 @@ self.displayLink = nil;
194197
`CFTimeInterval`值为`readOnly`,表示两次屏幕刷新之间的时间间隔。需要注意的是,该属性在`targe`t的`selector`被首次调用以后才会被赋值。`selector`的调用间隔时间计算方式是:**调用间隔时间 = duration × frameInterval**。
195198

196199

197-
#### 特点
200+
###特点
198201

199202
- **刷新频率固定**
200203

@@ -207,56 +210,28 @@ self.displayLink = nil;
207210

208211
CADisplayLink可以确保系统渲染每一帧的时候我们的方法都被调用,从而保证了动画的流畅性。
209212

210-
GCD定时器
211-
---
213+
##GCD定时器
214+
212215
**GCD定时器**和NSTimer是不一样的,NSTimer受RunLoop影响,但是GCD的定时器不受影响,因为通过源码可知RunLoop也是基于GCD的实现的,所以GCD定时器有非常高的精度。关于GCD的使用可一看看[这篇博客](http://www.cnblogs.com/pure/archive/2013/03/31/2977420.html)
213216

214-
#### 使用方法
217+
###使用方法
215218
创建GCD定时器定时器的方法稍微比较复杂,看下面的代码:
216219

217-
```objc
218-
// 定时时间
219-
int interval = 1;
220-
221-
// 创建全局队列
222-
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
223-
224-
// 创建定时器
225-
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
226-
227-
// 设置定时器 interval * NSEC_PER_SEC 定时间隔几秒
228-
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval * NSEC_PER_SEC, 0);
229-
230-
dispatch_source_set_event_handler(timer, ^{
231-
232-
dispatch_async(dispatch_get_main_queue(), ^{
233-
234-
// 需要执行的代码
235-
});
236-
});
237-
238-
// 开启定时器
239-
dispatch_resume(timer);
240-
241-
// 关闭定时器
242-
dispatch_source_cancel(timer);
243-
```
244-
245-
#### 单次的延时调用
220+
####单次的延时调用
246221
NSObject中的`performSelector:withObject:afterDelay:`以及 `performSelector:withObject:afterDelay:inModes:` 这两个方法在调用的时候会设置当前 runloop 中 `timer` ,前者设置的 `timer``NSDefaultRunLoopMode` 运行,后者则可以指定 **NSRunLoop**`mode` 来执行。我们上面介绍过 runloop 中 `timer``UITrackingRunLoopMode` 被挂起,就导致了代码就会一直等待 `timer` 的调度,解决办法在上面也有说明。
247222

248223
不过我们可以用另一套方案来解决这个问题,就是使用GCD中的 `dispatch_after` 来实现单次的延时调用:
249224

250-
```objc
225+
```
251226
double delayInSeconds = 2.0;
252227
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
253228
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
254229
[self someMethod];
255230
});
256231
```
257232

258-
#### 循环调用
259-
```objc
233+
####循环调用
234+
```
260235
// 创建GCD定时器
261236
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
262237
@@ -298,14 +273,14 @@ dispatch_source_cancel(_timer);
298273
- 创建的`timer`一定要有`dispatch_suspend(_timer)``dispatch_source_cancel(_timer)`这两句话来指定出口,否则定时器将不执行,若我们想无限循环可将 `dispatch_source_cancel(_timer)` 写在一句永不执行的`if`判断语句中。
299274

300275

301-
使用场景
302-
---
276+
##使用场景
277+
303278
介绍完iOS中的各种定时器,接下来我们来说说这几种定时器在开发中的几种用法。
304279
###短信重发倒计时
305280

306281
短信倒计时使我们登录注册常用的功能,一般设置为60s,实现方法如下:
307282

308-
```objc
283+
```
309284
// 计时时间
310285
@property (nonatomic, assign) int timeout;
311286
@@ -375,12 +350,12 @@ dispatch_source_cancel(_timer);
375350

376351
效果如下:
377352

378-
![](http://ww3.sinaimg.cn/large/006tNc79jw1faspxkoemhj30ci0m8mxy.jpg)
353+
![](http://upload-images.jianshu.io/upload_images/2178672-3d4d1353bcc36026.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
379354

380-
[代码的gitHub链接](https://github.com/qiubaiying/BYTimer)
355+
##### [代码链接](https://github.com/qiubaiying/BYTimer)
381356

382357

383-
### 每个几分钟向服务器发送数据
358+
###每个几分钟向服务器发送数据
384359

385360
在有定位服务的APP中,我们需要每个一段时间将定位数据发送到服务器,比如每5s定位一次每隔5分钟将再统一将数据发送服务器,这样会处理比较省电。
386361
一般程序进入后台时,定时器会停止,但是在定位APP中,需要持续进行定位,APP在后台时依旧可以运行,所以在后台定时器也是可以运行的。
@@ -391,7 +366,7 @@ dispatch_source_cancel(_timer);
391366

392367
这里我们使用**NSTimer**来创建一个每个5分钟执行一次的定时器.
393368

394-
```objc
369+
```
395370
#import <Foundation/Foundation.h>
396371
397372
typedef void(^TimerBlock)();
@@ -406,7 +381,7 @@ typedef void(^TimerBlock)();
406381
407382
```
408383

409-
```objc
384+
```
410385
#import "BYTimer.h"
411386
412387
@interface BYTimer ()
@@ -438,12 +413,18 @@ typedef void(^TimerBlock)();
438413
}
439414
440415
@end
441-
442416
```
443417

444-
该接口的实现很简单,就是**NSTimer**创建了一个300s执行一次的定时器,但是要注意定时器需要加入`NSRunLoopCommonModes`中。
418+
该接口的实现很简单,就是 **NSTimer** 创建了一个300s执行一次的定时器,但是要注意定时器需要加入`NSRunLoopCommonModes`中。
419+
420+
要使定时器在后台能运行,app 就需要在 [后台常驻](http://waitingyuan.blog.163.com/blog/static/2155781652014111133150534/)
421+
422+
# 结语
445423

446-
最后,要使定时器在后台能运行,app就需要在[后台常驻](http://waitingyuan.blog.163.com/blog/static/2155781652014111133150534/)
424+
最后总结一下:
447425

426+
NSTimer 使用简单方便,但是应用条件有限。
448427

428+
CADisplayLink 刷新频率与屏幕帧数相同,用于绘制动画。具体使用可看我封装好的一个 [水波纹动画](https://github.com/qiubaiying/WaterRippleView)
449429

430+
GCD定时器 精度高,可控性强,使用稍复杂。

0 commit comments

Comments
 (0)