1.block是ios中的一種比較特殊的數據類型,可參考C語言的函數指針
是用來保存一段代碼,可以在恰當的時間在取出來調用。
2.聲明block屬性的時候需要使用copy;
2.1.全局塊(_NSConcreteGlobalBlock)
全局塊存儲在靜態區,block不訪問外界變量,既不在棧也不在堆,此時就是全局塊 。
2.2.棧塊(_NSConcreateStackBlock)
訪問外部變量的block實際上是先放在棧區。(從棧拷貝到堆)
2.3.堆塊(_NSConcreateMallocBlock)
訪問外界變量的block默認存放在堆中,實際上是先放在棧區,然后又自動拷貝到堆區,自動釋放。
復制到堆上是為了保存block的狀態。(因為在棧上block在其變量作用域結束之后會唄釋放掉)延長其生命周期。(引用計數增加)
3.__block的作用
__blockint b = 10;
int a = 10;
void (^myBlock)() = ^{
NSLog(@"b = %@“,b);
NSLog(@"a = %@“,a);
};
b = 30;
a = 30;
myBlock();
上訴代碼中打印出來a = 10 ;b = 30;
block會把a變量復制為自己私有的const變量,只是一個值的傳遞
__block修飾符起到的作用是觀察到該變量被block所持有,就將該變量的內存存放到堆中,也就是說是一個指針的傳遞。
所以在沒有__block修飾時,在block內不可以修改變量,在block代碼塊后面修改變量不會影響block里面的值。有__block修飾時,在block內可以修改變量,在block代碼塊后面已經調用block前,修改變量,則block里面的值也跟著修改。
4.循環引用——-某個類將 block 作為自己的屬性變量,然后該類在 block 的方法體里面又使用了該類本身
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic , copy) void (^myBlock)(void);
@end
@implementation ViewController
- (void)CircularReferenceBlock{
self.myBlock = ^{
[self downloadData];
};
}
我們聲明了一個block屬性,所以self對block有個強引用,而在block里面,又對self進行一次強引用,形成了一個閉環,內存不能釋放,造成內存泄露
解決方法是打破這個閉環,加入
__weak typeof(self)weakSelf = self;
- (void)CircularReferenceBlock{
self.myBlock = ^{
[weakSelf downloadData];//加入weakSelf后,block對self就由強引用變成肉引用,這樣在self銷毀后,myBlock也會被銷毀,打破了這個循環引用。
};
}
[UIView animateWithDuration:1 animations:^{
[self doSomething];
}];
上述uiview的動畫中,只有block對self一次強引用,self沒有對block進行引用,所以沒有循環引用
__block int i =0;
Sample*s = [[Sample alloc]init];
__weak typeof(Sample) *weakS = s;
self.block1= ^{
while(i <10) {
i++;
__strong Sample* strongS = weakS;
NSLog(@"bbbbb %@",strongS);
[NSThread sleepForTimeInterval:1];
}
};
self.block2= ^{
__strong typeof(weakS) strongS = weakS;
//NSLog(@"aaa %@",strongS.s);
strongS =nil;
};
self.block2();
self.block1();
上述代碼如果不加strongS,weakS會為nil;一般都會寫__strong避免出現nil的情況。