iOS 之GCD和Block

1。GCD之dispatch queue

http://www.cnblogs.com/scorpiozj/archive/2011/07/25/2116459.html

2。iOS中GCD的魔力

http://blog.csdn.net/favormm/article/details/6453260

3。官方 ,内容真的很多

http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html

http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1

4.详解IOS开发应用之并发Dispatch Queues

http://mobile.51cto.com/iphone-283323.htm

5。斯坦福大学关于gcd的讲义

http://www.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/Lecture 13_0.pdf

gcd其实就是牛逼简化版的多线程。gcd和block是亲兄弟,所以学习gcd前需要了解block,不知道也没事,看看代码就明白了。

ios种GCD

GCD是和block紧密相连的,所以最好先了解下block(可以看我之前收藏的一篇文章).GCD是C level的函数,这意味着它也提供了C的函数指针作为参数,方便了C程序员.

下面首先来看GCD的使用:

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

async表明异步运行,block代表的是你要做的事情,queue则是你把任务交给谁来处理了.(除了async,还有sync,delay,本文以async为例).

之所以程序中会用到多线程是因为程序往往会需要读取数据,然后更新UI.为了良好的用户体验,读取数据的操作会倾向于在后台运行,这样以避免阻塞主线程.GCD里就有三种queue来处理.

1. Main queue:

  顾名思义,运行在主线程,由dispatch_get_main_queue获得.和ui相关的就要使用Main Queue.

2.Serial quque(private dispatch queue,其中dispatch_queue_t就是一种)

 每次运行一个任务,可以添加多个,执行次序FIFO. 通常是指程序员生成的,比如:

NSDate *da = [NSDate date]; NSString *daStr = [da description]; 

const char *queueName = [daStr UTF8String];
 dispatch_queue_t myQueue = dispatch_queue_create(queueName, NULL);

3. Concurrent queue(global dispatch queue,其中dispatch_time_t就是一种):

可以同时运行多个任务,每个任务的启动时间是按照加入queue的顺序,结束的顺序依赖各自的任务.使用dispatch_get_global_queue获得.

所以我们可以大致了解使用GCD的框架:

dispatch_async(getDataQueue,^{ //获取数据,获得一组后,刷新UI. dispatch_aysnc (mainQueue,^{ //UI的更新需在主线程中进行 }; } )

iosblocks是对象,它封装了一段代码,这段代码可以在任何时候执行。Blocks可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似,但是有区别:blocksinline的,并且它对局部变量是只读的。

Ios4已经直接支持blocks

Blocks的定义:

         int (^Multiply)(int, int) = ^(int num1, int num2) {return num1 * num2;};

定义了一个Multiplyblocks对象,它带有两个int参数,返回int。等式右边就是blocks的具体实现,注意{}blocks体里的;。

Blocks可以访问局部变量,但是不能修改。

              int multiplier = 7;

     int (^myBlock)(int) = ^(int num) {

         multiplier ++;//编译报错

         return num * multiplier;

     };

如果要修改就要加关键字:__block

         __block int multiplier = 7;

     int (^myBlock)(int) = ^(int num) {

         multiplier ++;//这样就可以了

         return num * multiplier;

     };

作为函数的参数,blocks某种意义上替代了回调函数或者delegate。当函数调用了,假设某个事件触发,这时blocks里的内容就会运行。这样有利于代码的整合和阅读,你不需要到处去实现委托方法了。

系统API中已经有很多支持blocks参数了

·       Completion handlers

·       Notification handlers

·       Error handlers

·       Enumeration

·       View animation and transitions

·       Sorting


函数原型

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

async表明异步运行,.(除了async,还有sync,delay,本文以async为例).

queue则是你把任务交给谁来处理了

block代表的是你要做的事情

queue有三种

Main: tasks execute serially on your application’s main thread Concurrent: tasks start executing in FIFO order, but can run concurrently. Serial: tasks execute one at a time in FIFO order

  • (1)serial queues(串行队列)又称私有调度队列(private),一般用再对特定资源的同步访问上。我们可以根据需要创建任意数量的串行队列,每一个串行队列之间是并发的。
  • (2)并行队列,又称global dispatch queue。并行队列虽然可以并发的执行多个任务,但是任务开始执行的顺序和其加入队列的顺序相同。我们自己不能去创建并行调度队列。只有三个可用的global concurrent queues。
  • (3)main dispatch queue 是一个全局可用的串行队列,其在行用程序的主线程上执行任务。此队列的任务和应用程序的主循环(run loop)要执行的事件源交替执行。因为其运行在应用程序的主线程,main queue经常用来作为应用程序的一个同步点

先看一段代码

view plain

  1. @interface UIImageView (DispatchLoad)    
  2. - (void) setImageFromUrl:(NSString*)urlString;    
  3. - (void) setImageFromUrl:(NSString*)urlString     
  4.               completion:(void (^)(void))completion;    
  5. @end 

view plain

  1. #import "UIImageView+DispatchLoad.h"    
  2. @implementation UIImageView (DispatchLoad)    
  3. - (void) setImageFromUrl:(NSString*)urlString {    
  4.     [self setImageFromUrl:urlString completion:NULL];    
  5. }    
  6. - (void) setImageFromUrl:(NSString*)urlString     
  7.               completion:(void (^)(void))completion {    
  8.         
  9.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   
  10.             
  11.         NSLog(@"Starting: %@", urlString);    
  12.         UIImage *avatarImage = nil;     
  13.         NSURL *url = [NSURL URLWithString:urlString];    
  14.         NSData *responseData = [NSData dataWithContentsOfURL:url];   
  15.         avatarImage = [UIImage imageWithData:responseData];    
  16.         NSLog(@"Finishing: %@", urlString);    
  17.             
  18.         if (avatarImage) {    
  19.             dispatch_async(dispatch_get_main_queue(), ^{    
  20.                 self.image = avatarImage;    
  21.             });    
  22.             dispatch_async(dispatch_get_main_queue(), completion);    
  23.         }    
  24.         else {    
  25.             NSLog(@"-- impossible download: %@", urlString);    
  26.         }    
  27.     });       
  28. }    
  29. @end

以上代码主要是实现,图像异步加载。

分解一下:

1>添加到gcd队列

view plain

  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

这个代码主要实现,将图像加载block添加到queue队列中,

view plain

  1. dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),

这个是获取全局并行队列(global dispatch queue),系统队列,只有3个。

2>加载图像。这个滤过

3>通知或更新主线程

view plain

  1. dispatch_async(dispatch_get_main_queue(), ^{    
  2.                 self.image = avatarImage;    
  3.             });    
  4.             dispatch_async(dispatch_get_main_queue(), completion); 

“block的一个优势是可以使用其自己作用域外的变量,例如,一个block可以读取其父作用域的变量值,此值是copy到了block heap的数据结构中。当block被加入到dispatch queue中,这些值通常为只读形式。”

而更新UI只能在主线程中实现,所以调用主线程函数 completion

这样就完成了异步加载图像的流程。

当想要任务按照某一个特定的顺序执行时,串行队列是很有用的。串行队列在同一个时间只执行一个任务。我们可以使用串行队列代替锁去保护共享的数据。和锁不同,一个串行队列可以保证任务在一个可预知的顺序下执行。

和并发队列不同,我们要自己去创建和管理串行队列,可以创建任意数量的串行队列。当我们创建串行队列时,应出于某种目的,如保护资源,或者同步应用程序的某些关键行为。

下面的代码表述了怎么创建一个自定义的串行队列,函数dispath_queue_create需要两个参数,队列的名字,队列的属性。调试器和性能工具显示队列的名字帮助我们去跟踪任务是如何执行,队列的属性被保留供将来使用,应该为NULL

  1. dispatch_queue_t queue;  
  2. queue = dispatch_queue_create("com.example.MyQueue", NULL);

除了自己创建的自定义队列,系统会自动的给我创建一个串行队列并和应用程序的主线程绑定到一起。下面讲述如何获得它。

贴几段斯坦福大学关于gcd的代码,这段代码逐步演示了如何修正错误,其中用到的既是串行队列

1。这个是原始代码

view plain

  1. - (void)viewWillAppear:(BOOL)animated  
  2. {  
  3.     NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:photo.URL]; 
  4.     UIImage *image = [UIImage imageWithData:imageData];  
  5.     self.imageView.image = image;  
  6.     self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); 
  7.     self.scrollView.contentSize = image.size; 
  8. }  

2。这个是采用gcdd的代码,里面有错误3处

view plain

  1. - (void)viewWillAppear:(BOOL)animated  
  2. {  
  3.     dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); 
  4.     dispatch_async(downloadQueue, ^{  
  5.          NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:photo.URL]; 
  6.          UIImage *image = [UIImage imageWithData:imageData];  
  7.          self.imageView.image = image;  
  8.          self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); 
  9.          self.scrollView.contentSize = image.size; 
  10.     });  
  11. }  

3。第一个错误,UI更新只能在主线程中 Problem! UIKit calls can only happen in the main thread!

改正后如下:

view plain

  1. - (void)viewWillAppear:(BOOL)animated  
  2. {  
  3.     dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); 
  4.     dispatch_async(downloadQueue, ^{  
  5.          NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:photo.URL]; 
  6.         dispatch_async(dispatch_get_main_queue(), ^{
  7.              UIImage *image = [UIImage imageWithData:imageData]; 
  8.              self.imageView.image = image;  
  9.              self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); 
  10.              self.scrollView.contentSize = image.size; 
  11.          });  
  12. }); }  

4。第二个错误,NSManagedObjectContext并不是线程安全的,gcd中访问成员变量有危险

Problem! NSManagedObjectContext is not thread safe,

so we can’t call photo.URL in downloadQueue’s t

改正后如下:

view plain

  1. - (void)viewWillAppear:(BOOL)animated  
  2. {  
  3.   NSString *url = photo.URL; 
  4.     dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); 
  5.     dispatch_async(downloadQueue, ^{  
  6.         NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:url];
  7.         dispatch_async(dispatch_get_main_queue(), ^{  
  8.             UIImage *image = [UIImage imageWithData:imageData]; 
  9.             self.imageView.image = image;  
  10.             self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); 
  11.             self.scrollView.contentSize = image.size; 
  12. }); });  
  13. }  

5。第三个错误,队列创建后没有释放,内存泄露

view plain

  1. - (void)viewWillAppear:(BOOL)animated  
  2. {  
  3.     NSString *url = photo.URL;  
  4.     dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); 
  5.     dispatch_async(downloadQueue, ^{  
  6.         NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:url]; 
  7.         dispatch_async(dispatch_get_main_queue(), ^{  
  8.             UIImage *image = [UIImage imageWithData:imageData]; 
  9.             self.imageView.image = image;  
  10.             self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height); 
  11.             self.scrollView.contentSize = image.size; 
  12. }); });  
  13.    dispatch_release(downloadQueue); //won’t actually go away until queue is empty }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值