Block
Block
1.什么是Block
- Block是iOS中一种比较特殊的数据类型
- Block是苹果官方特别推荐使用的数据类型, 应用场景比较广泛
+ 动画
+ 多线程
+ 集合遍历
+ 网络请求回调
+ 用来保存某一段代码, 可以在恰当的时间再取出来调用
+ 功能类似于函数和方法
2.block的格式
- Block的定义格式
返回值类型 (^block变量名)(形参列表) = ^(形参列表) {
};
-block最简单形式
void (^block名)() = ^{代码块;}
例如:
void (^myBlock)() = ^{ NSLog(@"lalala"); };
-block带有参数的block的定义和使用
void (^block名称)(参数列表)
= ^ (参数列表) { // 代码实现; }
例如:
void (^myBlock)(int) = ^(int num){ NSLog(@"num = %i", num); };
-带有参数和返回值的block
返回类型 (^block名称)(参数列表)
= ^ (参数列表) { // 代码实现; }
例如:
int (^myBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; };
-调用Block保存的代码
block变量名(实参);
// 注意: 利用typedef给block起别名, 和指向函数的指针一样, block变量的名称就是别名
函数指针使用
typedef int (*calculate) (int, int); int main(int argc, const char * argv[]) { calculate sumP = sum; int res = sumP(10, 20); NSLog(@"res = %i", res); calculate minusP = minus; res = minusP(10, 20); NSLog(@"res = %i", res); return 0; }
block和typedef
block使用
int main(int argc, const char * argv[]) { int (^sumBlock) (int, int) = ^(int value1, int value2){ return value1 + value2; }; int res = sumBlock(10 , 20); NSLog(@"res = %i", res); int (^minusBlock) (int, int) = ^(int value1, int value2){ return value1 - value2; }; res = minusBlock(10 , 20); NSLog(@"res = %i", res); return 0; }
block起别名
typedef int (^calculteBlock)(int , int); int main(int argc, const char * argv[]) { calculateBlock sumBlock = ^(int value1, int value2){ return value1 + value2; }; int res = sumBlock(10, 20); NSLog(@"res = %i", res); calculateBlock minusBlock = ^(int value1, int value2){ return value1 - value2; }; res = minusBlock(10, 20); NSLog(@"res = %i", res); return 0;
Block应用场景
问题1:block的应用场景是什么?
答:当发现代码的前面和后面都是一样的时候, 这个时候就可以使用block
Block注意事项
问题1:怎样访问和修改block外的值?
答: 1.block中可以访问外面的变量
int a = 10;
void (^myBlock)() = ^{
NSLog(@"a = %i",
a);
};
myBlock();
问题2:为什么不可以在block中修改外界变量的值?
答:
- 默认情况下, 不可以在block中修改外界变量的值,
- 因为block中的变量和外界的变量并不是同一个变量
- 如果block中访问到了外界的变量, block会将外界的变量拷贝一份到堆内存中
- 因为block中使用的外界变量是copy的, 所以在调用之前修改外界变量的值, 不会影响到block中copy的值
int a =
10;
NSLog(@"&a = %p", &a);
void (^myBlock)() = ^{
// a = 50;
NSLog(@"&a
= %p", &a);
NSLog(@"a = %i",
a);
};
a = 20;
myBlock();
问题3:__block的应用场景?
答: 如果想在block中修改外界变量的值, 必须在外界变量前面加上__block
__block int a =
10;
NSLog(@"&a = %p", &a);
void (^myBlock)() = ^{
a = 50;
NSLog(@"&a = %p",
&a);
NSLog(@"a =
%i", a);
};
myBlock();
NSLog(@"a = %i", a);
问题4: 为什么不加__block不能在block中修改外界变量的值?
答:加上__block之后就是地址传递, 所以可以在block中修改外界变量的值
int a = 10;
void (^myBlock)() = ^{
// a = 10;
NSLog(@"a = %i",
a);
};
myBlock();
问题5:block是存储在堆中还是栈中?
答:
- 默认情况下block存储在栈中, 如果对block进行一个copy操作, block会转移到堆中
- 如果block在栈中, block中访问了外界的对象, 那么不会对对象进行retain操作
- 但是如果block在堆中, block中访问了外界的对象, 那么会对外界的对象进行一次retain
问题6:怎么对block进行内存管理?
答:
- 如果在block中访问了外界的对象, 一定要给对象加上block, 只要加上了block, 哪怕block在堆中, 也不会对外界的对象进行retain
- 如果是在ARC开发中就需要在前面加上__weak
__block Person *p = [[Person alloc] init]; // 1
问题7:如何避免block出现循环引用?
答: 1.使用一个用__weak 修饰的值指针保存对象 2.或者使用Block_copy(myBlock)
MRC
__block Person *p = [[Person alloc] init]; // 1
ARC
//Person *p =
[[Person alloc] init];
// __weak Person *weakP = p;
NSLog(@"retainCount
= %lu", [p retainCount]);
void (^myBlock)() = ^{
NSLog(@"p = %@", p); //
2
// NSLog(@"p = %p",
weakP);
NSLog(@"block retainCount =
%lu", [p retainCount]);
};
Block_copy(myBlock);//将block对象转移到堆中
myBlock();
[p release]; 1