GCD电动机延时停止电路图操作怎么停止并释放

iOS -- GCD之延迟与定时器 - Fydevelop的博客 - CSDN博客
iOS -- GCD之延迟与定时器
iOS-定时器
我们开发常用的定时器有三种:NSTimer,CADisplyLink,CGD
本文详细说一下CGD的延迟与定时器方法。文章最后,也会说说GCD与前两个的区别。
直接上代码,首先是延迟的代码:
其中的delayInSeconds就是延迟的时间,执行之后,输出台会在2s之后,打印.
延迟的代码还算固定,但是GCD的定时器,新手上手会有一坑。我先上代码:
我最开始,按照网上说的代码,是没有将dispatch_source_t定义成属性,导致了我的handler代码块里的代码没有执行,因为timer对象被提前释放了,所以要给timer对象持有住,就没问题了。
我上一下最后输出台的代码
到这里就完成了。最后我说一下GCD与NSTimer,CADisplayLink的区别:
1.GCD是独立于RunLoop的,也就是不用管子线程的RunLoop,而NSTimer就要去做管理。
2.GCD可以将时间间隔定到纳秒。 可用于需要精确定时的地方。
3.GCD在内存的管理上也比NSTimer省心,因为NSTimer容易造成内存泄露。
我的热门文章
即使是一小步也想与你分享IOS开发(63)之GCD执行延迟操作
使用Dispatch_after ,能够在你想指定一定数量的延迟之后,使用 GCD 来执行代码。今天我们就来学习一下。
2 代码实例
ZYAppDelegate.m
- (void) printString:(NSString *)paramString{&
&&& NSLog(@&%@&, paramString);&
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions&
&&&& 推迟三秒执行printString方法&
&&&& withObject:传的参数&
&&& [self performSelector:@selector(printString:) withObject:@&Grand Central Dispatch& afterDelay:3.0];&
&&& self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];&
&&& // Override point for customization after application launch.&
&&& self.viewController = [[[ZYViewController alloc] initWithNibName:@&ZYViewController& bundle:nil] autorelease];&
&&& self.window.rootViewController = self.viewC&
&&& [self.window makeKeyAndVisible];&
&&& return YES;&
- (void) printString:(NSString *)paramString{
&&& NSLog(@&%@&, paramString);
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
&&&& 推迟三秒执行printString方法
&&&& withObject:传的参数
&&& [self performSelector:@selector(printString:) withObject:@&Grand Central Dispatch& afterDelay:3.0];
&&& self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
&&& // Override point for customization after application launch.
&&& self.viewController = [[[ZYViewController alloc] initWithNibName:@&ZYViewController& bundle:nil] autorelease];
&&& self.window.rootViewController = self.viewC
&&& [self.window makeKeyAndVisible];
&&& return YES;
运行3秒后控制台结果:
17:04:52.710 GCDAfterTest[2385:c07] Grand Central Dispatch
ZYAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions&
&&& //设置时间为2&
&&& double delayInSeconds = 2.0;&
&&& //创建一个调度时间,相对于默认时钟或修改现有的调度时间。&
&&& dispatch_time_t delayInNanoSeconds =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);&
&&& //推迟两纳秒执行&
&&& dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);&
&&& dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void){&
&&&&&&& NSLog(@&Grand Center Dispatch!&);&
&&& self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];&
&&& // Override point for customization after application launch.&
&&& self.viewController = [[[ZYViewController alloc] initWithNibName:@&ZYViewController& bundle:nil] autorelease];&
&&& self.window.rootViewController = self.viewC&
&&& [self.window makeKeyAndVisible];&
&&& return YES;&
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
&&& //设置时间为2
&&& double delayInSeconds = 2.0;
&&& //创建一个调度时间,相对于默认时钟或修改现有的调度时间。
&&& dispatch_time_t delayInNanoSeconds =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
&&& //推迟两纳秒执行
&&& dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
&&& dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void){
&&&&&&& NSLog(@&Grand Center Dispatch!&);
&&& self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
&&& // Override point for customization after application launch.
&&& self.viewController = [[[ZYViewController alloc] initWithNibName:@&ZYViewController& bundle:nil] autorelease];
&&& self.window.rootViewController = self.viewC
&&& [self.window makeKeyAndVisible];
&&& return YES;
运行2秒后控制台结果
17:06:27.023 GCDAfterTest2[] Grand Center Dispatch!
ZYAppDelegate.m
void processSomething(void *paramContext){&
&&& NSLog(@&Processing...&);&
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions&
&&& //设置时间&
&&& double delayInSeconds = 2.0;&
&&& dispatch_time_t delayInNanoSeconds =&
&&& dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);&
&&& dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);&
&&& //调用C函数processSomething&
&&& dispatch_after_f(delayInNanoSeconds, concurrentQueue,&
&&&&&&&&&&&&&&&&&&&& NULL,&
&&&&&&&&&&&&&&&&&&&& processSomething);&
&&& self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];&
&&& // Override point for customization after application launch.&
&&& self.viewController = [[[ZYViewController alloc] initWithNibName:@&ZYViewController& bundle:nil] autorelease];&
&&& self.window.rootViewController = self.viewC&
&&& [self.window makeKeyAndVisible];&
&&& return YES;&
void processSomething(void *paramContext){
&&& NSLog(@&Processing...&);
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
&&& //设置时间
&&& double delayInSeconds = 2.0;
&&& dispatch_time_t delayInNanoSeconds =
&&& dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
&&& dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
&&& //调用C函数processSomething
&&& dispatch_after_f(delayInNanoSeconds, concurrentQueue,
&&&&&&&&&&&&&&&&&&&& NULL,
&&&&&&&&&&&&&&&&&&&& processSomething);
&&& self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
&&& // Override point for customization after application launch.
&&& self.viewController = [[[ZYViewController alloc] initWithNibName:@&ZYViewController& bundle:nil] autorelease];
&&& self.window.rootViewController = self.viewC
&&& [self.window makeKeyAndVisible];
&&& return YES;
运行2秒后控制台结果
17:07:27.660 GCDAfterTest3[] Processing...iOS的GCD中如何关闭或者杀死一个还没执行完的后台线程? - 知乎23被浏览8096分享邀请回答@interface Canceller
BOOL _shouldCancel;
- (void)setShouldCancel:(BOOL)shouldCancel;
- (BOOL)shouldCancel;
@implementation Canceller
- (void)setShouldCancel:(BOOL)shouldCancel {
_shouldCancel = shouldCancel;
- (BOOL)shouldCancel {
return _shouldCancel;
static void test(int a){
static Canceller * canceller = nil;
[canceller setShouldCancel:YES];
[canceller release];
dispatch_suspend(q);
dispatch_release(q);
canceller = [[Canceller alloc] init];
q=dispatch_get_global_queue(0,0);
dispatch_async(q,^ {
while(![canceller shouldCancel]){NSLog(@"query %d",a);sleep(2);}
06 条评论分享收藏感谢收起1. sleepForTimeInterval,此函数会卡住当前线程,一般不用
&span style=&font-size:18&&[NSThread sleepForTimeInterval:3];&/span&
2. performSelector,定制好延迟任务后,不会卡主&当前线程&(3秒后执行download:方法)
&span style=&font-size:18&&[self performSelector:@selector(download:) withObject:@&http://555.jpg& afterDelay:3];&/span&
3.3秒后回到&主线程&执行block中的代码
&span style=&font-size:18&&dispatch_queue_t queue = dispatch_get_main_queue();&/span&&span style=&font-size:18&&&span style=&font-size:18&&dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
NSLog(@&------task------%@&, [NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
NSLog(@&------task------%@&, [NSThread currentThread]);
4.3秒后自动开启&新线程&执行block中的代码
&span style=&font-size:18&&dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);&/span&&span style=&font-size:18&&&span style=&font-size:18&&dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
NSLog(@&------task------%@&, [NSThread currentThread]);
});&/span&
本文已收录于以下专栏:
相关文章推荐
Created by mac on 16/4/27.
Copyright (c) 2016年 mac....
1.Difference between shallow copy and deep copy?
浅复制和深复制的区别?
答案:浅层复制:只复制指向对象的指针,而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和...
程序员升职加薪指南!还缺一个“证”!
CSDN出品,立即查看!
.cn/thread--1.html
TTL集成电路的主要型式为晶体管-晶体管逻辑门(transist...
基础知识:
1.C++或Java中的异常处理机制的简单原理和应用。
当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsExce...
此份面试题包含40个题目,是现在网上能搜索到的一个比较热的一份,但是答案并不是很详细和完整,基本答案来着cocoaChina,和一些自己的补充。
1.Difference
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)GCD使用经验与技巧浅谈 - 不积跬步 无以至千里 不积小流 无以成江海 - ITeye博客
博客分类:
GCD(Grand Central Dispatch)可以说是Mac、iOS开发中的一大“利器”,本文就总结一些有关使用GCD的经验与技巧。
dispatch_once_t必须是全局或static变量
这一条算是“老生常谈”了,但我认为还是有必要强调一次,毕竟非全局或非static的dispatch_once_t变量在使用时会导致非常不好排查的bug,正确的如下:
static dispatch_once_t onceT
dispatch_once(&onceToken, ^{
其实就是保证dispatch_once_t只有一份实例。
dispatch_queue_create的第二个参数
dispatch_queue_create,创建队列用的,它的参数只有两个,原型如下:
dispatch_queue_t dispatch_queue_create ( const char *label, dispatch_queue_attr_t attr );
在网上的大部分教程里(甚至Apple自己的文档里),都是这么创建串行队列的:
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
看,第二个参数传的是“NULL”。 但是dispatch_queue_attr_t类型是有已经定义好的常量的,所以我认为,为了更加的清晰、严谨,最好如下创建队列:
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", DISPATCH_QUEUE_CONCURRENT);
常量就是为了使代码更加“易懂”,更加清晰,既然有,为啥不用呢~
dispatch_after是延迟提交,不是延迟运行
先看看官方文档的说明:
Enqueue a block for execution at the specified time.
Enqueue,就是入队,指的就是将一个Block在特定的延时以后,加入到指定的队列中,不是在特定的时间后立即运行!。
看看如下代码示例:
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
NSLog(@"Begin add block...");
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:10];
NSLog(@"First block done...");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), queue, ^{
NSLog(@"After...");
结果如下:
20:57:27.122 GCDTest[6] Begin add block...
20:57:37.127 GCDTest[1] First block done...
20:57:37.127 GCDTest[1] After...
从结果也验证了,dispatch_after只是延时提交block,并不是延时后立即执行。所以想用dispatch_after精确控制运行状态的朋友可要注意了~
正确创建dispatch_time_t
用dispatch_after的时候就会用到dispatch_time_t变量,但是如何创建合适的时间呢?答案就是用dispatch_time函数,其原型如下:
dispatch_time_t dispatch_time ( dispatch_time_t when, int64_t delta );
第一个参数一般是DISPATCH_TIME_NOW,表示从现在开始。
那么第二个参数就是真正的延时的具体时间。
这里要特别注意的是,delta参数是“纳秒!”,就是说,延时1秒的话,delta应该是“”=。=,太长了,所以理所当然系统提供了常量,如下:
#define NSEC_PER_SEC ull
#define USEC_PER_SEC 1000000ull
#define NSEC_PER_USEC 1000ull
关键词解释:
NSEC:纳秒。
USEC:微妙。
NSEC_PER_SEC,每秒有多少纳秒。
USEC_PER_SEC,每秒有多少毫秒。(注意是指在纳秒的基础上)
NSEC_PER_USEC,每毫秒有多少纳秒。
所以,延时1秒可以写成如下几种:
dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
dispatch_time(DISPATCH_TIME_NOW, 1000 * USEC_PER_SEC);
dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC * NSEC_PER_USEC);
最后一个“USEC_PER_SEC * NSEC_PER_USEC”,翻译过来就是“每秒的毫秒数乘以每毫秒的纳秒数”,也就是“每秒的纳秒数”,所以,延时500毫秒之类的,也就不难了吧~
dispatch_suspend != 立即停止队列的运行
dispatch_suspend,dispatch_resume提供了“挂起、恢复”队列的功能,简单来说,就是可以暂停、恢复队列上的任务。但是这里的“挂起”,并不能保证可以立即停止队列上正在运行的block,看如下例子:
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"After 5 seconds...");
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"After 5 seconds again...");
NSLog(@"sleep 1 second...");
[NSThread sleepForTimeInterval:1];
NSLog(@"suspend...");
dispatch_suspend(queue);
NSLog(@"sleep 10 second...");
[NSThread sleepForTimeInterval:10];
NSLog(@"resume...");
dispatch_resume(queue);
运行结果如下:
00:32:09.903 GCDTest[4] sleep 1 second...
00:32:10.910 GCDTest[4] suspend...
00:32:10.910 GCDTest[4] sleep 10 second...
00:32:14.908 GCDTest[6] After 5 seconds...
00:32:20.911 GCDTest[4] resume...
00:32:25.912 GCDTest[6] After 5 seconds again...
可知,在dispatch_suspend挂起队列后,第一个block还是在运行,并且正常输出。
结合文档,我们可以得知,dispatch_suspend并不会立即暂停正在运行的block,而是在当前block执行完成后,暂停后续的block执行。
所以下次想暂停正在队列上运行的block时,还是不要用dispatch_suspend了吧~
“同步”的dispatch_apply
dispatch_apply的作用是在一个队列(串行或并行)上“运行”多次block,其实就是简化了用循环去向队列依次添加block任务。但是我个人觉得这个函数就是个“坑”,先看看如下代码运行结果:
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_apply(3, queue, ^(size_t i) {
NSLog(@"apply loop: %zu", i);
NSLog(@"After apply");
运行的结果是:
00:55:40.854 GCDTest[9] apply loop: 0
00:55:40.856 GCDTest[9] apply loop: 1
00:55:40.856 GCDTest[9] apply loop: 2
00:55:40.856 GCDTest[9] After apply
看,明明是提交到异步的队列去运行,但是“After apply”居然在apply后打印,也就是说,dispatch_apply将外面的线程(main线程)“阻塞”了!
查看官方文档,dispatch_apply确实会“等待”其所有的循环运行完毕才往下执行=。=,看来要小心使用了。
避免死锁!
dispatch_sync导致的死锁
涉及到多线程的时候,不可避免的就会有“死锁”这个问题,在使用GCD时,往往一不小心,就可能造成死锁,看看下面的“死锁”例子:
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"I am block...");
你可能会说,这么低级的错误,我怎么会犯,那么,看看下面的:
- (void)updateUI1 {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"Update ui 1");
[self updateUI2];
- (void)updateUI2 {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"Update ui 2");
在你不注意的时候,嵌套调用可能就会造成死锁!所以为了“世界和平”=。=,我们还是少用dispatch_sync吧。
dispatch_apply导致的死锁!
啥,dispatch_apply导致的死锁?。。。是的,前一节讲到,dispatch_apply会等循环执行完成,这不就差不多是阻塞了吗。看如下例子:
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_apply(3, queue, ^(size_t i) {
NSLog(@"apply loop: %zu", i);
dispatch_apply(3, queue, ^(size_t j) {
NSLog(@"apply loop inside %zu", j);
这端代码只会输出“apply loop: 1”。。。就没有然后了=。=
所以,一定要避免dispatch_apply的嵌套调用。
灵活使用dispatch_group
很多时候我们需要等待一系列任务(block)执行完成,然后再做一些收尾的工作。如果是有序的任务,可以分步骤完成的,直接使用串行队列就行。但是如果是一系列并行执行的任务呢?这个时候,就需要dispatch_group帮忙了~总的来说,dispatch_group的使用分如下几步:
创建dispatch_group_t
添加任务(block)
添加结束任务(如清理操作、通知UI等)
下面着重讲讲在后面两步。
添加任务可以分为以下两种情况:
自己创建队列:使用dispatch_group_async。
无法直接使用队列变量(如使用AFNetworking添加异步任务):使用dispatch_group_enter,dispatch_group_leave。
自己创建队列时,当然就用dispatch_group_async函数,简单有效,简单例子如下:
dispatch_group_async(group, queue, ^{
当你无法直接使用队列变量时,就无法使用dispatch_group_async了,下面以使用AFNetworking时的情况:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
dispatch_group_enter(group);
[manager GET:@"" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
dispatch_group_leave(group);
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
dispatch_group_leave(group);
使用dispatch_group_enter,dispatch_group_leave就可以方便的将一系列网络请求“打包”起来~
添加结束任务
添加结束任务也可以分为两种情况,如下:
在当前线程阻塞的同步等待:dispatch_group_wait。
添加一个异步执行的任务作为结束任务:dispatch_group_notify
这两个比较简单,就不再贴代码了=。=
使用dispatch_barrier_async,dispatch_barrier_sync的注意事项
dispatch_barrier_async的作用就是向某个队列插入一个block,当目前正在执行的block运行完成后,阻塞这个block后面添加的block,只运行这个block直到完成,然后再继续后续的任务,有点“唯我独尊”的感觉=。=
值得注意的是:
dispatchbarrier\(a)sync只在自己创建的并发队列上有效,在全局(Global)并发队列、串行队列上,效果跟dispatch_(a)sync效果一样。
既然在串行队列上跟dispatch_(a)sync效果一样,那就要小心别死锁!
dispatch_set_context与dispatch_set_finalizer_f的配合使用
dispatch_set_context可以为队列添加上下文数据,但是因为GCD是C语言接口形式的,所以其context参数类型是“void *”。也就是说,我们创建context时有如下几种选择:
用C语言的malloc创建context数据。
用C++的new创建类对象。
用Objective-C的对象,但是要用__bridge等关键字转为Core Foundation对象。
以上所有创建context的方法都有一个必须的要求,就是都要释放内存!,无论是用free、delete还是CF的CFRelease,我们都要确保在队列不用的时候,释放context的内存,否则就会造成内存泄露。
所以,使用dispatch_set_context的时候,最好结合dispatch_set_finalizer_f使用,为队列设置“析构函数”,在这个函数里面释放内存,大致如下:
void cleanStaff(void *context) {
dispatch_set_finalizer_f(queue, cleanStaff);
详细用法,请看我之前写的Blog
其实本文更像是总结了GCD中的“坑”=。=
至于经验,总结一条,就是使用任何技术,都要研究透彻,否则后患无穷啊~
感谢:http://tutuge.me//something-about-gcd/
浏览: 2513835 次
来自: China
很棒的一篇文章,感谢楼主分享
获取原型对象的三种方法&script&functi ...
属性的重写与删除与原型链无关&script&fun ...
为什么没生效啊!!!弄了几次了!!!
史上最详细的iOS之事件的传递和响应机制-原理篇http:// ...}

我要回帖

更多关于 延时摄影 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信