Block
平常编程中经常用,对于Block语法感觉很怪异,有一些细节总是想不起来,今天正好看到了别人写点Block用法很巧妙,特意来总结一下。
##Block语法基础
Block单独使用:
Block的声明:
1
NSString *(^intToString)(NSUInteger para);
Block的定义:
1
2
3intToString = ^NSString *(NSUInteger para){
return [NSString stringWithFormat:@"%d",para];
};Block的调用:
1
intToString(1);
Block作为参数:
1
string = [self convertIntToString:2 usingBlockObject:intToString];
Block内联:
1
2
3
4string = [self convertIntToString:3 usingBlockObject:^NSString *(NSUInteger para) {
return [NSString stringWithFormat:@"%d",para];
return result;
}];修改Block之外的变量
Block中调用外部变量是对变量的拷贝,修改的并不是变量本身,而是他的替身
。基本类型的Block变量等效于全局变量、或静态变量,要想修改变量本身需要使用__block修饰。1
2
3
4__block int a = 0;
void (^foo)(void) = ^{
a = 1;
}1
2
3
4
5
6
7
8
9__block int base = 100;
base += 100;
BlkSum sum = ^ long (int a, int b) {
base += 10;
return base + a + b;
};
base++;
printf("%ld\n",sum(1,2));//输出214,计算顺序是先base++,再进入Block体中base+=10,base+a+b
printf("%d\n",base);//输出211Block的copy:
Block被另一个Block使用时,另一个Block被copy到堆上时,被使用的Block也会被copy。但作为参数的Block是不会发生copy的。1
typedef long (^BlkSum)(int, int);
1
2
3
4
5
6
7
8void foo() {
int base = 100;
BlkSum blk = ^ long (int a, int b) {
return base + a + b;
};
NSLog(@"%@", blk); // <__NSStackBlock__: 0xbff34da0>
bar(blk);
}1
2
3
4
5
6
7
8
9
10
11
12void bar(BlkSum sum_blk) {
NSLog(@"%@",sum_blk); // <__NSStackBlock__: 0xbff34da0>,并不会发生copy
void (^blk) (BlkSum) = ^ (BlkSum sum) {
NSLog(@"%@",sum); // <__NSStackBlock__: 0xbff34da0>,无论blk在堆上还是栈上,作为参数的Block不会发生copy。
NSLog(@"%@",sum_blk); // <__NSStackBlock__: 0xbff34da0>,当blk在堆上时,sum_blk也会被copy到堆上
};
blk(sum_blk); // blk在栈上 <__NSStackBlock__: 0xbff34d60>
blk = [[blk copy] autorelease]; // <__NSMallocBlock__: 0x7880fa50> 被copy到了堆上
blk(sum_blk); // blk在堆上 blk:<__NSMallocBlock__: 0x7880fa50> sum_blk:<__NSStackBlock__: 0xbff34da0>
}Block作为属性:
Block作为属性要用copy
属性,将Block从栈内存复制到堆内存。
同时要注意循环引用的情况,如下面代码就会产生循环引用1
2
3self.myblock = ^{
[self doSomething];
};解决方法是对
self
做weak
处理1
__weak typeof(self) weakSelf = self;
##Block的三种类型
- NSGlobalBlock:类似函数,位于text段
- NSStackBlock:位于栈内存,函数返回后Block将无效
NSMallocBlock:位于堆内存。
NSGlobalBlock
,我们只要实现一个没有对周围变量没有引用的Block,就会显示为是它。而如果其中加入了对定义环境变量的引用,就是NSStackBlock
。那么NSMallocBlock
又是哪来的呢?malloc一词其实大家都熟悉,就是在堆上分配动态内存时。如果你对一个NSStackBlock
对象使用了Block_copy()或者发送了copy消息,就会得到NSMallocBlock
。这一段中的几项结论可从代码实验得出。1
2
3
4//NSGlobalBlock:
float (^sum)(float, float) = ^(float a, float b){
return a + b;
};1
2
3
4
5//NSStackBlock:
NSArray *testArr = @[@"1", @"2"];
void (^TestBlock)(void) = ^{
NSLog(@"testArr :%@", testArr);
};1
2//NSMallocBlock:
//NSStackBlock做copy操作,这合Block属性的copy属性是吻合的
##Block使用技巧
tableView中加载数据后的界面刷新:
1
2
3[self buildTestDataThen:^{
[self.tableView reloadData];
}];1
2
3
4
5
6
7
8
9
10
11- (void)buildTestDataThen:(void (^)(void))then {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 获取数组
// 获取完成后回调
dispatch_async(dispatch_get_main_queue(), ^{
!then ?: then();
});
});
}线程锁:
1
2
3
4
5
6
7//声明
static void aspect_performLocked(dispatch_block_t block) {
static OSSpinLock aspect_lock = OS_SPINLOCK_INIT;
OSSpinLockLock(&aspect_lock);
block();
OSSpinLockUnlock(&aspect_lock);
}1
2
3
4//使用
aspect_performLocked(^{
//异步操作
});
未完待续