// main.m
// 07-Block 演练
//
// Created by LNJ on 14-6-25.
// Copyright (c) 2014 年 itcast. All rights reserved.
//
#import<Foundation/Foundation.h>
voidblockDemo2();
voidblockDemo3();
voidblockDemo4();
intmain(intargc,constchar* argv[])
{
@autoreleasepool{
NSArray*array =@[@(5),@(2),@(3),@(1),@(6)];
//给数组排序,块代码的返回值,比较结果
// NSOrderedAscending = -1L,
// NSOrderedSame = 0,
// NSOrderedDescending = 1
NSArray*result = [arraysortedArrayUsingComparator:^NSComparisonResult(idobj1,idobj2) {
// 5, 2, 3, 1, 6
// 2, 5, 3, 1, 6
// 2, 5, 1, 3, 6
// 2, 5, 1, 3, 6
// 1, 5, 2, 3, 6
// 1, 5, 2, 3, 6
// 1, 2, 3, 5, 6
NSLog(@"%@ - %@", obj1, obj2);
//升序排序
// return [obj1 compare:obj2];
//降序排序
// return [obj2 compare:obj1];
//乱序,随机返回-1, 0, 1
// 0~2随机数- 1
return arc4random_uniform( 3) - 1;
}];
NSLog( @"==== %@", result);
}
return 0;
}
/** 两种数组遍历的对比 */
void blockDemo5()
{
NSArray *array = @[@(1), @(2), @(3), @(4)];
[array enumerateObjectsUsingBlock:^( NSNumber *num, NSUInteger idx, BOOL *stop) {
NSLog( @"%@", num);
// idx == 2 时,退出循环
if (idx == 2) {
*stop = YES;
}
}];
NSLog( @"------");
int index = 0;
for ( NSNumber *num in array) {
NSLog( @"%@", num);
// 第二项,退出循环
index++;
if (index == 2) {
break;
}
}
}
/** 外部变量访问 3 ,常见面试题 */
void blockDemo4()
{
// 指针包含指针的地址,和指向的地址
NSMutableString *str = [ NSMutableString stringWithString: @"hello"];
NSLog( @"%p %p", &str, str);
void(^myBlock)() = ^ {
// 修改指针 指向内存空间里 的内容
[str setString: @"world"];
NSLog( @"%p %p", &str, str);
NSLog( @"%@", str);
};
myBlock();
}
/** 外部变量访问 2 ,常见面试题 */
void blockDemo3()
{
// 如果要在 block 中修改外部变量的值,需要使用 __block
// __block 还可以在 block 被执行时, ** 同步外部变量最新的数值 ****
// 提示:为了保证代码的可读性,通常不建议使用 __block
__block int x = 10;
NSLog( @"%p", &x);
// 在定义 block 时,如果 block 中使用到外部的 “ 局部 ” 变量, block 会建立该变量的 ** 副本 **( 会记录当前 x 的数值 )
void(^myBlock)() = ^ {
// 在使用外部变量时,默认不允许在块代码中直接修改外部变量的数值
// x = 80;
NSLog( @"%d", x);
NSLog( @"=== %p", &x);
};
x = 20;
myBlock();
NSLog( @"%d", x);
}
/** 外部变量访问 1 ,常见面试题 */
void blockDemo2()
{
int x = 10;
NSLog( @"%p", &x);
// 在定义 block 时,如果 block 中使用到外部的 “ 局部 ” 变量, block 会建立该变量的副本 ( 会记录当前 x 的数值 )
void(^myBlock)() = ^ {
// 在使用外部变量时,默认不允许在块代码中直接修改外部变量的数值
// x = 80;
NSLog( @"%d", x);
NSLog( @"%p", &x);
};
// x = 20;
myBlock();
NSLog( @"%d", x);
}
/** block 的定义 */
void blockDemo1()
{
// block 定义,是准备好一段代码片段,在需要的时候执行
// block 是 C 语言的格式
//
// 输入: inlineblock
// 格式:返回类型 (^blockName) ( 参数类型 ) = ^( 形参列表 ) { 代码实现 };
// 提示:如果没有参数,格式可以简化
// 格式:返回类型 (^blockName) () = ^ { 代码实现 };
void (^myBlock)() = ^ {
NSLog( @"hello block");
};
// 调用 block
myBlock();
void (^sumBlock)( int, int) = ^( int x, int y) {
NSLog( @"%d", x + y);
};
sumBlock( 10, 20);
}
// __weak IWGeneralViewController *weakSelf = self;
// typeof 可以获取括号中传递的值的真实类型
// typeof(10) a = 10; == int a = 10;
// __weak typeof(clearCache) weakClearCache = clearCache;
// __weak typeof(self) weakSelf = self;
// 如果是用__weak 修饰, 当对象销毁之后会自动将变量的值设置为nil
// 而如果__unsafe_unretained 不会
__unsafe_unretained typeof(clearCache) weakClearCache = clearCache;
__unsafe_unretained typeof( self) weakSelf = self;
如何在开发中,避免 block 出现循环引用呢
1> 每次碰到 self 的时候,要小心,需要思考一下
2> 充分利用 dealloc 方法
3
解决方法:
__weak CZViewController *weakSelf = self;
*/
// block 引用外部变量时,默认会做 copy 操作, copy 本身也会做一次强引用
// 在现在的代码中,如果 block 中有对 self 的强引用,出现循环引用的情况
// 解决方法,在 oc 中,对象默认都是强引用, __weak 可以变成弱引用
一、BOLCK
(一)简介
BLOCK是什么?苹果推荐的类型,效率高,在运行中保存代码。用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行。
BOLCK和函数的相似性:(1)可以保存代码(2)有返回值(3)有形参(4)调用方式一样。
标识符 ^
(二)基本使用
(1)定义BLOCK变量
Int (^SumBlock)(int,int);//有参数,返回值类型为int
Void (^MyBlock)();//无参数,返回值类型为空
(2)利用block封装代码
(3)Block访问外部变量
1)Block内部可以访问外部变量;
2)默认情况下,Block内部不能修改外部的局部变量
3)给局部变量加上__block关键字,则这个局部变量可以在block内部进行修改。
(4)利用typedef定义block类型(和指向函数的指针很像)
Typedef int(^MyBlock)(int ,int);
以后就可以利用这种类型来定义block变量了。
MyBlock a,b;
a=^(int a,int b){return a-b;};
MyBlock b2=^(int n1,int n2){return n1*n2;};
二、Protocol(协议)
(一)简介
1.Protocol:就一个用途,用来声明一大堆的方法(不能声明成员变量),不能写实现。
2.只要某个类遵守了这个协议,就拥有了这个协议中的所有方法声明。
3.只要父类遵守了某个协议,那么子类也遵守。
4.Protocol声明的方法可以让任何类去实现,protocol就是协议。
5.OC不能继承多个类(单继承)但是能够遵守多个协议。继承(:),遵守协议(< >)
6.基协议:<NSObject>是基协议,是最根本最基本的协议,其中声明了很多最基本的方法。
7.协议可以遵守协议,一个协议遵守了另一个协议,就可以拥有另一份协议中的方法声明。
(二)基本使用
创建一个协议
遵守协议
完成协议中声明的方法的实现
测试程序
1.协议的定义
@protocol 协议名称 <NSObject>
//方法声明列表
@end;
2.如何遵守协议
(1)类遵守协议
@protocol 类名:父类名 <协议名称1,协议名称2>
@end
(2)协议遵守协议
@protocol 协议名称 <其他协议名称]]]]>
@end;
3.协议方法声明中的关键字
(1)required (默认)要求实现,若没有实现则警告但不报错
(2)Optional 不要求实现
4.定义变量时遵守协议的限制
类名<协议名称> *变量名 NSObject<.Myprotocol> *obj;
Id <协议名称> 变量名 id <.Myprotocol> obj1;
5.Property中声明的属性也可以做遵守协议的限制
@property (nonatomic ,strong ) 类名<协议名称> *属性名;
@property (nonatomic ,strong ) id<协议名称> 属性名;
6.补充知识:协议本身写在.h头文件中,但也可以定义在任何地方。当这个协议只有这个类使用遵守时,一般把协议写在这个类里边,当这个协议需要多个类去实现时,就写在外边单独的文件中。
A对象是请求者 B对象是响应者
代理的使用
- A制定协议(申明代理方法)
@protocol HMTourViewDelegate <NSObject>
- (void)tourViewBtnDidClick:(HMTourView *)tourView
@end
- A定义代理属性
@property(nonatomic,weak)id <协议名称> delegate;
- B遵守协议
@interface ViewController ()<HMTourViewDelegate> 任何对象遵守协议都可以成为代理
- B成为代理
tourView.delegate = self;
- B在代理的类实现方法
#pragma mark - 代理方法
/**
HMTourViewDelegate
*/
- (void)tourViewBtnDidClick:(HMTourView *)tourView {
}
- A让代理帮助调用方法实现功能
if ([self.delegate respondsToSelector:@selector(tourViewBtnDidClick:)]) {
[self.delegate tourViewBtnDidClick:self];
};
通知
- A制定通知名称
- .h文件低端写通知名称
@interface HMTourView : UIView
@end
UIKIT_EXTERN NSString *const HMMuneBtnDidClickNotification;
- .m顶端写通知的真名称 (字符串)
#import "HMTourCell.h"
NSString *const HMMuneBtnDidClickNotification = @"HM";
@implementationHMTourView
@end
- A发布通知(通知内容为字典)(多种方法)
[[NSNotificationCenter defaultCenter] postNotificationName:HMMuneBtnDidClickNotification object:self userInfo:@{@"key":str}];
- B注册通知(方法多种)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(xx:) name:HMMuneBtnDidClickNotification object:mune];
- B完成通知方法,实现功能
#pragma mark - 通知
- (void)xx:(NSNotification *)notification {
// NSLog(@"%@",notification);
NSDictionary *dic = notification.userInfo;
self.titleLabel.text = [NSString stringWithFormat:@"第%@个按钮",dic[@"key"]];
}
- B销毁通知
#pragma mark - 记得消除通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Block
- A定义block别名
typedef void(^MnueBlock)(NSString *str);
- A定义block类型属性
@property(nonatomic,copy)MnueBlock mnueBlock;
- B传入block代码块参数给A属性
mune.mnueBlock = ^ (NSString *str){
NSLog(@"%@",str);
self.titleLabel.text = [NSString stringWithFormat:@"第%@个按钮",str];
};
- A调用block完成功能(block可以传入参数)
- Block是一个数据类型,有自己的ISA指针,可以保存代码块,多用于参数的传递,只有调用Block的时候才会执行Block中的代理块
- 定义一个block的时候需要用copy,代码块是在栈区分配,一旦离开作用域就会被释放,所以要用copy
- __Block关键字理解
- 正常情况下,在Block{ }中不能对外面的变量进行更改(报错)
- 给想要更改的变量加上__Block关键字即可
- Block理解
- 自身view功能不能实现时,自定义一个block请求控制器去实现
- block传的参数是给控制器用来实现方法
- 解决Block循环引用问题
- 当在大括号中出现self或者下划线的属性,可能造成死循环
- __weak typeof (self) weakSelf =self typeof( )会自动识别括号中的对象类型
- 与delegate区别
- delegate回调更多的时面向过程,block则面向结果
- 代理存在的意义,面向过程思想,将业务逻辑模块化
- 代理是一对一,在代理中,只有声明并实现了代理协议的对象才能调用
- 通知是多对多
- 监听器可以监听多个不同条件的通知,也可以监听多个人发布的通知,不需要知道谁发通知谁接收通知
- 监听范围是整个应用
/*
1.addObserver:通知的接收者--通知监听者
2.selector:通知接收者接收到通知之后,调用它的那一个方法进行处理.方法一定要添加一个:传递参数---系统会默认将当前通知对象做为参数传递给方法处理者
3.name:接收的通知的名称,如果为nil,那么就可以接收到任意名称的通知
4.object:通知的发布者,如果为nil,则可以接收到任何人发布的通知
*/
[center addObserver:p1 selector:@selector(rent:) name:@"一房一厅" object:h1];
[center addObserver:p2 selector:@selector(rent:) name:nil object:nil];
//3.发布通知
/*
1.postNotificationName:通知名称
2.object:谁发布的通知
3.userInfo:当前通知的相关信息
*/
// [center postNotificationName:@"一房一厅" object:h1 userInfo:@{@"floor":@"3",@"price":@"300"}];
[center postNotificationName:@"一房一厅" object:h1userInfo:@{@"floor":@"3",@"price":@"300"}];
协议和代理对于一个新手来说确实不讨好理解,也有很多的iOS开发的老手对此是懂非懂的。网上的很多博文只是讲了怎么使用,并没有说的很明白。下面我谈一下我的理解。
1.你要先搞明白,协议和代理为什么会出现,也就是说它存在的意义是什么,解决了什么问题。
协议和代理是模块化开发和封装的产物。
先讲一个小故事帮助大家理解:
老王有一家餐馆,刚刚开始的时候规模很小,所以老王一个人做了所有的事情:扫地,做菜,迎宾,上菜,收银。但是后面随着规模的扩大,老王一个人就吃不消了,忙死也忙不过来了。这时候怎么办?大家都很清楚吧,招人呗!所以后面就有了服务员,收银员,大厨,保洁员。
这就意味着原先老王的工作按模块进行了拆分。
餐馆的工作流程(业务逻辑)简单来说是这样的:点餐->做菜->上菜->收银->打扫卫生。
转换成编程世界的模型就是这样的:业务不是很复杂的时候,我们把所有的功能都写在一个类里面,这个类暂且叫老王,理论上所有的事情和功能都可以写到这个类里面。做菜方法,上菜方法,打扫方法......就造成了老王这个类非常的庞大和臃肿,并且容易出错。
那我们开始招人了,新建了大厨类,服务员类,收银类,保洁类,这四个类。大厨类有做菜方法,服务员类点菜,上菜方法,收银类有收银方法,保洁类有打扫方法。
仅仅这样还是不行的,因为模块开发必然就有模块分化以后模块之间的通信问题。大厨类只做菜 但是菜做好了怎么办,必须及时的上菜,让顾客享用。但是大厨自己不能上菜,所以大厨必须抛出菜做好了的信号,具体这个菜上不上,怎么上,就不是大厨关心的了。
2.协议和代理所发挥的作用
老王交代大厨,你只管做菜,菜做好了以后喊一声菜做好了(我见过一个餐馆是拉铃铛)。
那么老王跟大厨定的这个规矩就是协议(protocol),下面看代码:
DaChu.h
/**
* 下面是声明协议的固定格式,DaChuDelegate是协议的名称,因为是代理协议,名称格式为:类名+Delegate
*/
@protocol DaChuDelegate <NSObject>
- (void)doSomethingAftercaiZuohaole;
@end
@interface DaChu : NSObject
/**
* delegate 是dachu类的一个属性,weak 关键字是为了避免循环引用,<DaChuDelegate>表示遵守DaChuDelegate协议
* 更加直白点:在大厨心里有一个人接受他的菜好了的信号去做一些事情,具体这个人是谁,大厨不关心,这个人的代号是delegate
*/
@property (nonatomic, weak) id <DaChuDelegate> delegate;
- (void)kaiShiZuoCai;
@end
Dachu.m
#import "DaChu.h"
@implementation DaChu
- (void)kaiShiZuoCai{
NSLog(@"开始做菜");
sleep(2);
NSLog(@"做好菜了,该上菜了");
//下面这句是判断 一下delegate是否实现了doSomethingAftercaiZuohaole方法,如果delegate没有实现
//直接[self.delegate doSomethingAftercaiZuohaole];会crash
if ([self.delegate respondsToSelector:@selector(doSomethingAftercaiZuohaole)]) {
[self.delegate doSomethingAftercaiZuohaole];
}
}
@end
下面看一看laowang这个类里面的内容
#import "LaoWang.h"
#import "DaChu.h"
@interface LaoWang ()<DaChuDelegate>//<DaChuDelegate>表示遵守DaChuDelegate协议,并且实现协议里面的方法
@end
@implementation LaoWang
- (void)laoWangKaiYe{
NSLog(@"老王开业了");
DaChu *dachu1 = [[DaChu alloc] init];
dachu1.delegate = self;//说明老王充当代理的角色,负责接收菜好了的信号。
[dachu1 kaiShiZuoCai];//大厨开始做菜
}
- (void)doSomethingAftercaiZuohaole{
NSLog(@"老王知道了");//这里可以通知服务员去上菜了
}
@end
上面的这个过程,也可以看下图来理解:
Grand Central Dispatch,或者简称 GCD,是一个与 Block Object 产生工作的低级的 C API。GCD 真正的用途是将任务分配到多个核心又不让程序员担心哪个内核执行哪个任务。 在 Max OS X 上,多内核设备,包括笔记本,用户已经使用了相当长的时间。通过多核设备 比如 iPad2 的介绍,程序员能为 iOS 写出神奇的多核多线程 APP。
GCD 的核心是分派队列。不论在 iOS 还是 Max OS X 分派队列,正如我们快看到的是 由位于主操作系统的 GCD 来管理的线程池。你不会直接与线程有工作关系。你只在分派队 列上工作,将任务分派到这个队列上并要求队列来调用你的任务。GCD 为运行任务提供了 几个选择:同步执行、异步执行和延迟执行等。
// 主线程队列,由系统自动创建并且与应用撑血的主线程相关联。
// 要在主线程队列中,执行的Block
dispatch_async(mainQueue, ^(void) {
[[[UIAlertView alloc] initWithTitle:@"GCD"
message:@"GCD is amazing!"
delegate:nil cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];
});
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
dispatch_async_f 方法
void dispatch_async_f(dispatch_queue_t queue,void *context,dispatch_function_t work);
queue:指定执行该work的队列
void *context:所使用的 application-defined(应用程序范围内有效的,也就是全局的)级别的参数。这是个C语法,void * 是一个无类型指针。也就是说,用它可以指向任何内存数据。
work:在指定队列(queue 参数)中要执行的方法。在该方法中,第一个参数所指代的数据,也就是dispatch_async_f方法所使用的第二个参数(void *context)所指带的数据。
// 定义结构体
typedef struct{
char *title;
char *message;
char *cancelButtonTitle;
} AlertViewData;
// 定义dispatch_function_t 所执行的方法
void displayAlertView(void *paramContext){
AlertViewData *alertData = (AlertViewData *)paramContext;
NSString *title =[NSString stringWithUTF8String:alertData->title];
NSString *message =[NSString stringWithUTF8String:alertData->message];
NSString *cancelButtonTitle =[NSString stringWithUTF8String:alertData->cancelButtonTitle];
[[[UIAlertView alloc] initWithTitle:title message:message
delegate:nil
cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil, nil] show];
// 释放结构体所占用的内存
free(alertData);
}
// **执行dispatch_async_f
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 为结构体分配内存
AlertViewData *context = (AlertViewData *) malloc(sizeof(AlertViewData));
// 初始化结构体
if (context != NULL){
context->title = "GCD";
context->message = "GCD is amazing.";
context->cancelButtonTitle = "OK";
// GCD执行异步方法:指定主队列(mainQueue),传递结构体数据(context)来执行displayAlertView方法。
dispatch_async_f(mainQueue,(void *)context, displayAlertView);
}
dispatch_async 方法
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
dispatch_async(mainQueue1, ^(void) {
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
});
输出:
2013-03-27 15:45:54.501 DemoVideo[21802:707] Current thread = {name = (null), num = 1}
2013-03-27 15:45:54.503 DemoVideo[21802:707] Main thread = {name = (null), num = 1}
可见,dispatch_get_main_queue() 队列所执行的Block就是在主线程上执行的。
例如,你想下载一个图片并想在下载完成之后展现给用 户。下载过程却和 UI 没有任何关系。对于任何与 UI 无关的任务,你可以使用 GCD 中的全 局并发队列。它们允许同步和异步执行。如果你同步提交一个任务到一个并发队列,同时提交另一个同步任务到另一个并发队列;相对而言这两个同步任务将异步运行,因为他们运行在两个不同的并发队 列上。你想确定在 B 任务开始之前 A 任务完 成了。那么必须把它们同时提交一个相同的队列。
dispatch_get_global_queue 方法
dispatch_queue_t dispatch_get_global_queue(long priority,unsigned long flags);
priority:优先级
flags:暂时还没有用到,为0.
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
dispatch_sync 方法
void dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
queue:指定的队列
block:执行的代码Block
// 得到默认优先级队列
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(concurrentQueue, printFrom1To1000);// 同步执行
dispatch_sync(concurrentQueue, printFrom1To1000);// 同步执行
// 同步执行的Block
void (^printFrom1To1000)(void) = ^{
NSUInteger counter = 0;
for (counter = 1;counter <= 1000;counter++){
NSLog(@"Counter = %lu - Thread = %@",(unsigned long)counter, [NSThreadcurrentThread]);
}
};
在主队列、串行队列和并发队列上异步执行代码块才能见识到 GCD 的真正实力。你将会完全相信 GCD 是多线程应用的未来,并将完全取代 现代应用中的线程。
- (void) viewDidAppear:(BOOL)paramAnimated{
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block UIImage *image = nil;
dispatch_sync(concurrentQueue, ^{
// 同步下载图片
NSString *urlAsString =@"http://images.apple.com/mobileme/features/images/ipad_findyouripad_20100518.jpg";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSError *downloadError = nil;
NSData *imageData = [NSURLConnectionsendSynchronousRequest:urlRequest
returningResponse:nil
error:&downloadError];
if (downloadError == nil && imageData != nil){
image = [UIImage imageWithData:imageData];
}else if (downloadError != nil){
NSLog(@"Error happened = %@", downloadError);
} else {
NSLog(@"No data could get downloaded from the URL."); }
});
dispatch_sync(dispatch_get_main_queue(), ^{
// 直到下载图片完成,再调用主线程,更新UI
if (image != nil){
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[imageView setImage:image];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.view addSubview:imageView];
} else {
NSLog(@"Image isn't downloaded. Nothing to display.");
}
});
});
}
- (void)viewDidLoad{
[super viewDidLoad];
[self performSelector:@selector(printString:)
withObject:@"Grand Central Dispatch"
afterDelay:3.0];
}
- (void) printString:(NSString *)paramString{
NSLog(@"%@", paramString);
}
void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
when:所指定的时间
queue:指定的队列
block:执行的Block
- (void)viewDidLoad{
[super viewDidLoad];
double delayInSeconds = 2.0;
// 创建延期的时间 2S,因为dispatch_time使用的时间是纳秒,尼玛,比毫秒还小,太夸张了!!!
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(@"Output GCD !");
});
}
dispatch_time 方法
dispatch_time_t dispatch_time(dispatch_time_t when,int64_t delta);
when:指定的开始点,可以用 DISPATCH_TIME_NOW 来指定一个当前的时间点
delta:纳秒数
dispatch_after 方法
void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
when:时间点
queue:指定的队列
block:执行的Block
dispatch_after_f 方法
- (void)viewDidLoad{
[super viewDidLoad];
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_f(delayInNanoSeconds,concurrentQueue, @"GCD", processSomething);
}
void processSomething(void *paramContext){
NSLog(@"This is %@",paramContext);
}
static dispatch_once_t onceToken;
void (^executedOnlyOnce)(void) = ^{
static NSUInteger numberOfEntries = 0;
numberOfEntries++;
NSLog(@"Executed %lu time(s)", (unsigned long)numberOfEntries);
};
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_once(&onceToken, ^{
dispatch_async(concurrentQueue,executedOnlyOnce);
});
dispatch_once(&onceToken, ^{
dispatch_async(concurrentQueue,executedOnlyOnce);
});
dispatch_once 方法
void dispatch_once(dispatch_once_t *predicate,dispatch_block_t block);
predicate:单例标识符
block:执行的Block
dispatch_group_t 方法
typedef struct dispatch_group_s *dispatch_group_t;
dispatch_group_create 方法
dispatch_group_t dispatch_group_create(void);
创建一个调度组
dispatch_group_async 方法
void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
group:要分发到的调度组
queue:执行Block的队列
block:要执行的Block
将Block分发到指定的队列(用指定的队列来执行Block),并且将该Block加入到指定的调度组中。
dispatch_group_notify 方法
void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
当调度组中的所有Block被执行完成后,将调用被分配到指定队列的Block。
dispatch_release 方法
void dispatch_release(dispatch_object_t object);
object:调度对象
销毁指定的调度组。
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_group_t taskGroup = dispatch_group_create();// 创建一个调度组
dispatch_queue_t mainQueue = dispatch_get_main_queue();// 创建队列
// 任务1
// 将Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadTableView];
});
// 任务2
// 将Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadScrollView];
});
// 任务3
// 将Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadImageView];
});
// 当指定调度组(taskGroup)中的所有Block都执行完成后,将执行给定的Block,用指定的队列(mainQueue)。
dispatch_group_notify(taskGroup, mainQueue, ^{
// 指定的Block
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All tasks are finished"delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]show];
});
// 最后,必须release 掉调度组(taskGroup)
dispatch_release(taskGroup);
#pragma mark - 执行的多个方法
- (void) reloadTableView{
NSLog(@"%s", __FUNCTION__);
}
- (void) reloadScrollView{
NSLog(@"%s", __FUNCTION__);
}
- (void) reloadImageView{
NSLog(@"%s", __FUNCTION__);
}
2013-03-28 23:00:57.394 DemoVideo[25096:707] -[MoreViewController reloadTableView]
2013-03-28 23:00:57.395 DemoVideo[25096:707] -[MoreViewController reloadScrollView]
2013-03-28 23:00:57.396 DemoVideo[25096:707] -[MoreViewController reloadImageView]
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_async_f(taskGroup, mainQueue,(void *)self, reloadAllComponents);
dispatch_group_notify(taskGroup, mainQueue, ^{
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All Tasks are Finished"
delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
});
dispatch_release(taskGroup);
}
// 定义调度组要执行的C函数
void reloadAllComponents(void *context){
MoreViewController *self =(MoreViewController *)context;
[self reloadTableView];
[self reloadScrollView];
[self reloadImageView];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
// 创建指定的自定义的串行队列
dispatch_queue_t firstSerialQueue =dispatch_queue_create("com.pixolity.GCD.serialQueue1", NULL);
// 让队列异步执行Block
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0;
for (counter = 0; counter < 5; counter++){
NSLog(@"First iteration, counter = %lu", (unsigned long)counter); }
NSLog(@"Current thread = %@", [NSThread currentThread]);
});
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0; for (counter = 0;counter < 5;counter++){
NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);
NSLog(@"Current thread = %@", [NSThread currentThread]);
}
});
dispatch_async(firstSerialQueue, ^{ NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);
NSLog(@"Current thread = %@", [NSThread currentThread]);
}
});
// 销毁队列
dispatch_release(firstSerialQueue);
// 输出主队列,比较会发现,我们自定义的队列,并不在主线程上,效率还是蛮高的。
dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
dispatch_async(mainQueue1, ^(void) {
NSLog(@"Main thread = %@", [NSThread mainThread]);
});
}
// 定义任务1-C函数形式
void firstIteration(void *paramContext){
NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"First iteration, counter = %lu", (unsigned long)counter);
}
}
// 定义任务2-C函数形式
void secondIteration(void *paramContext){
NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);
}
}
// 定义任务3-C函数形式
void thirdIteration(void *paramContext){
NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);
}
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_queue_t firstSerialQueue =dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0);
dispatch_async_f(firstSerialQueue, NULL, firstIteration);
dispatch_async_f(firstSerialQueue, NULL, secondIteration);
dispatch_async_f(firstSerialQueue, NULL, thirdIteration);
dispatch_release(firstSerialQueue);
}
dispatch_semaphore_create 方法
dispatch_semaphore_t dispatch_semaphore_create(long value);
创建一个信号量对象
value:信号量的值,必须大于等于0。
什么是信号量?
我想举个例子你就会明白了。古时候执行某种命令需要令牌。创建一个信号量,就是创建一个命令。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
也就是说,一项任务semaphore,有3个令牌,就是说,最多可以同时分派3名不同的将领去执行。
dispatch_semaphore_wait
Waits for (decrements) a semaphore.
long dispatch_semaphore_wait(dispatch_semaphore_t dsema,dispatch_time_t timeout);
递减信号量。
dsema:信号量
timeout:等待信号量的策略
返回0,说明递减信号量成功。
也就是说,拿走一个令牌去执行某个任务。这时候,令牌数量会减去1。当令牌用完时,使用FIFO的原则进行等待。
dispatch_semaphore_signal
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
增加信号量
也就是说,某一个将领执行任务回来。并且将令牌上交。这样处于等待中的将领可以得到令牌并执行相应任务。
//主线程中
TestObj *obj = [[TestObj alloc] init];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
long thecount= dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"%ld",thecount);
[obj method1];
sleep(10);
dispatch_semaphore_signal(semaphore);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
long thecount= dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"----%ld",thecount);
[obj method2];
dispatch_semaphore_signal(semaphore);