objective-c的块语法与函数类似,但作用类似于函数指针,并且可以直接转化成函数指针。
1.块语法的声明和定义
声明:
void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int, char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
或者通过typedef:
typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;
块的声明类似于c的函数,不同的地方是必须在块名前加^,而且要是没有返回值必须或参数都必须要加void.
定义:
float (^oneFrom)(float);
oneFrom = ^(float aFloat) {
float result = aFloat - 1.0;
return result;
};
也可以简化着写:
float (^oneFrom)(float) = ^(float aFloat) {
float result = aFloat - 1.0;
return result;
};
也可以这样声明定义:
@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end
实现:
self.blockProperty = ^{
...
};
self.blockProperty();
2.在代码块中使用局部变量和全局变量
- (void)testMethod {
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
testBlock();
}
输出结果:Integer is: 42
块内是可以直接访问块外的变量。
再看下面代码:
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();
输出结果:Integer is: 42
输出结果没有变化,块只是捕获到一个常量值,这是因为块内的存储空间和非块内是不一样的,这是代码块的特点。若想改变可以用__block。定义一个__block变量就是让这个变量和块内共享内存空间,所以可以在块内修改并且影响到外部变量的值。
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();<span style="color:#666666;">
</span>
输出结果:
Integer is: 84并且可以在块内改变:
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
anInteger = 100;
};
testBlock();
NSLog(@"Value of original variable is now: %i", anInteger);
输出结果:
Integer is:42
Value of original variable is now: 100
如果访问的对象是一个自定义的类类型呢?
自定义类类型:
test.h
#import <Foundation/Foundation.h>
@interface test : NSObject
{
NSString *name;
}
@property (readwrite,assign) NSString * name;
@end
test.m
#import "test.h"
@implementation test
@synthesize name;
@end
test *t = [test new];
[t setName:@"123"];
void (^testBlock)(void) = ^{
NSLog(@"%@",[t name]);
[t setName:@"456"];
NSLog(@"%@",[t name]);
test *t2 = t;
[t2 setName:@"777"];
};
[t setName:@"789"];
testBlock();
输出结果:
789
456
3.代码块用作回调函数
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock
{
callbackBlock();
}
调用;
[self beginTaskWithCallbackBlock:^{NSLog(@"hello");}];
当有多个参数的时候,代码块必须要作为最后一个参数:
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;
4.应用场景
项目中经常遇到一些方法中的参数是代码块,如下:
异步线程:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"Block for asynchronous execution");
});
<pre name="code" class="objc">NSBlockOperation *block = [[NSBlockOperation alloc] init];
[block addExecutionBlock:^{
sleep(1);
NSLog(@"111");
}];
[block start];