Block:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
|
// main.m
// 块的使用
#import <Foundation/Foundation.h>
#include <stdlib.h>
typedef
void
(^DownloadURL)(
void
);
//获取用于下载URL的块
DownloadURL getDownloadURLBlock(NSString *url)
{
NSString *urlString = url;
return
^{
//下载URL
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
NSError *error;
NSDate *startTime = [NSDate date];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if
(data == nil) {
NSLog(@
"Error loading request %@"
, [error localizedDescription]);
}
else
{
NSDate *endTime = [NSDate date];
NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime];
NSLog(@
"Time taken to download %@ = %f seconds"
, urlString, timeInterval);
}
};
}
int
main(
int
argc,
const
char
* argv[]) {
@autoreleasepool {
//block可以理解为闭包或者lambda也可以是函数指针 也可以是匿名内部类
#pragma mark - 块的定义
/*定义块的语法格式如下:
^[块返回值类型] (形参类型1 形参1,形参类型2 形参2, ...){
//块执行体
}
*/
//定义不带参数、无返回值的块
void
(^printStr) (
void
) = ^(
void
){
NSLog(@
"这是块"
);
};
//使用printStr调用块
printStr();
//定义带参数、有返回值的块
double
(^hypot) (
double
,
double
) = ^(
double
num1 ,
double
num2){
return
sqrt
(num1 * num1 + num2 * num2);
};
//调用块,并输出块的返回值
NSLog(@
"%g"
, hypot(3,4));
//也可以先只定义块变量:定义带参数、无返回值的快
void
(^print) (NSString *);
//再将块赋值给指定的块变量
print = ^(NSString * info){
NSLog(@
"info参数为:%@"
, info);
};
//调用块
print(@
"测试块调用"
);
#pragma mark - 修改局部变量的值
/*块可以访问程序中局部变量的值,当块访问局部变量的值时,不允许修改局部变量的值
如果不希望在定义块时就把局部变量的值复制到块中,而是等到执行时才去访问、获取局部变量的值,
甚至希望块也可以改变局部变量的值,此时可以考虑使用__block修饰局部变量。*/
//定义__block修饰的全局变量
//int one = 1;
__block
int
my = 20;
void
(^printMy)(
void
) = ^(
void
){
//运行时访问、获取局部变量的值,此处输出45
NSLog(@
"%d"
, my);
//尝试对_block局部变量赋值是允许的
my = 30;
//one = 2; //Xcode会提示无法对one进行修改,除非用__block进行了修饰
//此处输出30
NSLog(@
"%d"
, my);
};
my = 45;
printMy();
//调用块
//由于块修改了__block局部变量的值,因此下面的代码输出30
NSLog(@
"块执行完后,my的值为:%d"
, my);
#pragma mark - 使用typedef定义块类型
/*使用typedef定义块类型的语法格式如下:
typedef 块返回值类型 (^块类型) (形参类型1 [形参名] ,形参类型2 [形参名] , ... );
*/
/*使用typedef可以定义块类型,定义了块类型后,该块类型主要有如下两个用途:
1.复用块类型,使用块类型可以重复定义多个块变量。
2.使用块类型定义函数参数,这样即可定义带块参数的函数。*/
//使用typedef定义块类型
typedef
void
(^FKPrintBlock) (NSString*);
//使用FKPrintBlock定义块变量,并将指定块赋给该变量
FKPrintBlock printt = ^(NSString * info){
NSLog(@
"%@"
, info);
};
//使用FKPrintBlock定义块变量,并将指定块赋值给该变量
FKPrintBlock loopPrint = ^(NSString * info){
for
(
int
i = 0 ; i < 2 ; i++){
NSLog(@
"%@"
, info);
}
};
//一次调用两个块
printt(@
"Objective-C"
);
loopPrint(@
"iOS"
);
#pragma mark - 作为方法的参数
/*作为方法声明的参数
//- (void)方法名:(返回值类型 (^)(参数类型))block的名称;
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
*/
NSArray *jingse = @[@
"锦瑟无端五十弦,"
,@
"一弦一柱思华年。"
,@
"庄生晓梦迷蝴蝶,"
,@
"望帝春心托杜鹃。"
,@
"沧海月明珠有泪,"
,@
"蓝田日暖玉生烟"
,@1,@NO];
//定义一个block块操作 return(^fpointer)(int,NS*...) = ^(int a,NS* B...){...};
void
(^Pblock1)(id,NSUInteger,
BOOL
*) = ^(id obj,NSUInteger idx,
BOOL
*stop){
NSLog(@
"%ld --> %@"
,idx,obj);
if
(idx == [jingse count]) {
*stop = YES;
}
};
//匿名block指针
[jingse enumerateObjectsUsingBlock:Pblock1];
//- (void)enumerateObjectsUsingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop));
//?????
// BOOL *stop = NO;
// for (int i = 0 ; stop; i++)
// Pblock1(jingse[i],i,stop);
#pragma mark - 块的内存管理
/*1)在运行程序时,块常量表达式会获得栈内存,因而会拥有与局部变量相同的生命周期。
因此,它们您必须被复制到永久存储区域(即堆)中,才能在定义它们的范围之外使用。
2)使用Block_copy()命令可以将块常量复制到堆中,使用Block_release()命令可以释放堆中的块常量.
3)在使用ARC时,只要块没有返回id类型值或将id类型值用作参数,编译器就会自动执行块的复制和释放操作。否则,就必须手动执行复制和释放操作。
4)在使用MRR时,__block变量不会被保留;而在使用ARC时,__block变量会被保留。这就意味着如果你在使用ARC时不想不想保留__block变量(如避免循环引用),还应对变量应用__weak存储类型修饰符*/
/*在MRR下使用
void (^greetingBlock)(void)
{
greetingBlock = [^{
NSLog(@"Hello Jabit");
} copy];
}
greetingBlock();
[greetingBlock release];*/
/*在MRR下使用
void (^greetingBlock)(id salutation);
{
greetingBlock = Block_copy(^(id salutation){
NSLog(@"%@, Jabit", salutation);
});
}
greetingBlock(@"Hello");
Block_release(greetingBlock);*/
#pragma mark - 在OC中使用block
/*1、作为变量
//1
返回值类型 (^block的名称)(参数类型) = ^返回值类型(参数) {...};
//2
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
2、作为属性
//1
@property (nonatomic, copy) 返回值类型 (^block的名称)(参数类型);
//2
@property (nonatomic, copy) returnType (^blockName)(parameterTypes);
3、作为方法声明的参数
//1
- (void)方法名:(返回值类型 (^)(参数类型))block的名称;
//2
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
4、作为方法实现的参数
//1
[对象/类 方法名:^返回值类型 (参数) {...}];
//2
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
5、使用typedef定义块类型
*/
#pragma mark - 使用块为数组排序
#define ArrayElements 10
//创建一个含有随机数值(0~99)的数组
NSMutableArray *numbers = [NSMutableArray arrayWithCapacity:ArrayElements];
for
(
int
elem=0; elem<ArrayElements; elem++) {
unsigned
int
value = arc4random() % 100;
[numbers addObject:[NSNumber numberWithUnsignedInt:value]];
}
NSLog(@
"Values:%@"
, numbers);
//记录未排序的数值
//以升序方式为数组数值排序
[numbers sortUsingComparator:^(id obj1, id obj2){
if
([obj1 integerValue] > [obj2 integerValue]) {
return
(NSComparisonResult)NSOrderedDescending;
}
if
([obj1 integerValue] < [obj2 integerValue]) {
return
(NSComparisonResult)NSOrderedAscending;
}
return
(NSComparisonResult)NSOrderedSame;
}];
NSLog(@
"Values:%@"
, numbers);
//记录已排序的数值
#pragma mark - 使用块加载URL
#define IndexURL @"http://www.wikipedia.com/index.html"
//为连接获取当前的运行循环
NSRunLoop *loop = [NSRunLoop currentRunLoop];
BOOL
__block downloadComplete = NO;
//创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:IndexURL]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if
(data == nil) {
NSLog(@
"Error loading request %@"
, [error localizedDescription]);
}
else
{
NSLog(@
"\n\tDownloaded %lu bytes from request %@\n"
, [data length], [request URL]);
}
downloadComplete = YES;
}];
//一直循环直到完成加载资源的操作为止(它会运行循环,接收输入源的事件,并执行所有相应的委托或回调方法,直到连接完成加载资源的操作为止
while
(!downloadComplete && [loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
#pragma mark - 使用块的并行编程方式
#define YahooURL @"http://www.yahoo.com/index.html"
#define ApressURL @"http://www.apress.com/index.html"
//创建任务请求(GCD API)
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建任务分组
dispatch_group_t group = dispatch_group_create();
//获取度量的当前时间
NSDate *startTime = [NSDate date];
//创建并分派异步任务
dispatch_group_async(group, queue1, getDownloadURLBlock(YahooURL));
dispatch_group_async(group, queue2, getDownloadURLBlock(ApressURL));
//使主进程等待,直到分组中的所有任务完成为止
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//为并行操作和日志检索时间信息
NSDate *endTime = [NSDate date];
NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime];
NSLog(@
"Time taken to download URLs concurrently = %f seconds\n"
, timeInterval);
}
return
0;
}
|