block的定義
// 無參數(shù)無返回值
void (^block)(void);
// 無參有返回值
int (^block1)(void);
// 有參有返回
int (^block2)(int number);
// 對(duì)block tydpef
typedef void(^valueBlock)(NSString *string);
@property (nonatomic, copy) valueBlock valueBlock;
block內(nèi)部使用變量
void test1() {
int a = 10;
void (^block)(void) = ^{
NSLog(@"a is %d", a);// a是局部變量坯台,block定義之后a就被銷毀了奋刽。
};
a = 20;
block();
}
void test2() {
__block int a = 10;// __block修飾會(huì)編譯成一個(gè)struct類型榆浓,在arc下會(huì)強(qiáng)引用肠缔,mrc下是將不會(huì)retain鸯两,可以避免循環(huán)引用忿项。
void (^block)(void) = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();
}
void test3() {
static int a = 10; // static 函數(shù)每次被調(diào)用蓉冈,普通局部變量都是重新分配,而靜態(tài)局部變量保持上次調(diào)用的值不變轩触。
void (^block)(void) = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();
}
int a = 10;
void test4() {
void (^block)(void) = ^{
NSLog(@"a is %d", a); // a是全局變量
};
a = 20;
block();
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
test1(); // 10
test2(); // 20
test3(); // 20
test4(); // 20
// 只有普通局部變量是傳值寞酿,其他情況都是傳址。
}
- 如果block訪問的外部變量是局部變量脱柱,那么就是值傳遞伐弹,外界變了不會(huì)影響里面。
- 如果block訪問的外部變量是__block或者static修飾或者是全局變量榨为,那么就是指針傳遞
block的內(nèi)存管理
- 無論當(dāng)前環(huán)境是ARC還是MRC惨好,只要block沒有訪問外部變量煌茴,block始終在全局區(qū)。
- MRC情況下
- block如果訪問外部變量日川,block在棧里
- 不能對(duì)block使用retain蔓腐,否則不能保存在堆里
- 只能使用copy,才能放到堆里龄句。
- ARC情況下
- block如果訪問外部變量回论,block在堆里
- block可以使用copy和strong,并且block是一個(gè)對(duì)象
block的循環(huán)引用
循環(huán)引用.png
這個(gè)代碼中shop指向Shop對(duì)象分歇,shop屬性myBlock指向Block傀蓉,block代碼指向Shop對(duì)象出現(xiàn)循環(huán)引用,一般Xcode會(huì)有提示职抡,這個(gè)很好葬燎。
參考這篇文章,對(duì)于block的循環(huán)引用缚甩,內(nèi)存管理萨蚕,作者寫的很詳細(xì),我就不寫了蹄胰。
block中的weakself什么時(shí)候加
不是什么時(shí)候都要加的岳遥,只有出現(xiàn)循環(huán)引用的時(shí)候才需要加,self->block->self.property/self->_ivar這樣的循環(huán)鏈時(shí)要加weakself
block傳值
- 在控制器間傳值可以使用代理或者block裕寨,使用block相對(duì)來說比較簡(jiǎn)潔浩蓉。
SecondViewController *secondVC = [[SecondViewController alloc] init];
secondVC.valueBlock = ^(NSString *string) {
NSLog(@"ViewController拿到了SecondVC的值%@", string);
self.textFild.text = string;
};
[self presentViewController:secondVC animated:YES completion:nil];
在secondVC中聲明一個(gè)block屬性
typedef void(^valueBlock)(NSString *string);
@interface SecondViewController : UIViewController
@property (nonatomic, copy) valueBlock valueBlock;
@end
在.m中實(shí)現(xiàn)方法
self.valueBlock(@"hello xiaofang");
這樣在textfild上就可以顯示第二個(gè)頁面?zhèn)鬟^來的字符串了。
block作為一個(gè)參數(shù)使用
在一個(gè)類中聲明一個(gè)帶block參數(shù)的方法
- (void)calculator:(int(^)(int result))block;
在m文件中實(shí)現(xiàn)方法
- (void)calculator:(int(^)(int result))block {
self.result = block(self.result);
NSLog(@"result = %d", self.result);
}
在其他類中調(diào)用方法
Shop *shop = [[Shop alloc] init];
// 調(diào)用 block用作參數(shù)
[shop calculator:^int(int result) {
result += 5;
return result;
}];
block作為返回值使用
在一個(gè)類中聲明一個(gè)返回值是block宾袜,并且block的返回值是改類
- (Shop *(^)(int a))add;
m文件中實(shí)現(xiàn)方法
- (Shop *(^)(int a))add {
return ^(int a) {
_result += a;
return self;
在其他類中調(diào)用
#pragma MARK - block作為返回值使用
- (void)test9 {
Shop *shop = [[Shop alloc] init];
shop.add(1).add(2).add(3);
NSLog(@"%d", shop.result);
}
總結(jié)block需要注意的點(diǎn)
- 在block內(nèi)部使用外部指針且造成循環(huán)引用的情況下需要使用
__weak
修飾外部指針typeof(type) weaktype = type;
- 在block內(nèi)部如果調(diào)用了延時(shí)函數(shù)還使用弱指針會(huì)取不到該指針捻艳,因?yàn)橐呀?jīng)被銷毀,需要block內(nèi)部再將弱指針強(qiáng)引用一下
__strong typeof(self) strongSelf = weakSelf;
Shop *shop = [[Shop alloc] init];
shop.string = @"welcom to my shop";
WeakSelf(shop);
shop.myBlock = ^{
StrongSelf(shop);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",shop.string);
});
// 注釋掉StrongSelf(shop) 延遲2秒執(zhí)行發(fā)現(xiàn)會(huì)娶不到弱指針庆猫,打印nill认轨。需要在block內(nèi)部將弱指針在強(qiáng)引用一下
};
shop.myBlock();
- 如果需要在block內(nèi)部需要外部變量的話需要使用
__block
修飾外部變量。