block的定義
// 無(wú)參數(shù)無(wú)返回值
void (^block)(void);
// 無(wú)參有返回值
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)存管理
- 無(wú)論當(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ì)來(lái)說(shuō)比較簡(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è)頁(yè)面?zhèn)鬟^(guò)來(lái)的字符串了。
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
修飾外部變量。