Block是將函數
及其執行上下文
封裝起來的對象
。能夠保存一段代碼,在須要的時候調用。javascript
格式爲: 返回值類型(^Block名字)(參數列表);
如:java
// 無參無返回
void (^aBlock)(void);
// 無參有返回
int(^aBlock)(void) ;
// 有參有返回
NSString* (^aBlock)(NSString * x, int y);
// 無參有返回
NSString* (^aBlock)(void);
複製代碼
@property(nonatomic,copy)NSString* (^ablock)(void);
複製代碼
typedef void (^Block)(void);
typedef int (^MyBlock)(int a, int b);
typedef void(^ConfirmBlock)(BOOL isOK);
typedef NSString *(^AlertBlock)(NSInteger alertTag);
複製代碼
賦值格式爲: Block變量名 = ^返回類型(參數列表){ 函數體 };
如:程序員
// 無參無返回
self.aBlock = ^{
NSLog(@"... ...");
};
// 無參有返回
self.ablock = ^NSString *{
NSLog(@"dd");
return @"dd";
};
// 有參有返回
self.ablock = ^NSString *(int a) {
return @"vv";
};
// 有參無返回
self.aBlock = ^(NSString *x, int y){
NSLog(@"mmm");
};
複製代碼
block由其所屬的類對象調用,指明要作什麼。block中包含的是一段代碼,含義是執行一些操做,具體什麼操做,至關於給屬性賦值,只是這裏給block賦一段代碼。markdown
由其所屬的類對象調用。相似方法調用 如:網絡
//無返回
self.ablock();
//有返回
NSString *result = self.ablock(2);
複製代碼
在處理異步問題的時候,例如HTTP請求,有點像javascript
的回調,在獲得回覆的時候更新主線程,而不會佔用主線程,比Delegate
邏輯好看多了;或者,當你要返回多個值又懶得建立一個類的時候。數據結構
#####1.傳遞數據(把數據傳遞出去、逆傳)異步
@interface PDMineVC : PDViewController
@property(nonatomic,copy)void (^rebackBlock)(NSString *flag);
@end
複製代碼
// 調用,把須要傳遞的信息 做爲參數
self.rebackBlock(@"425");
複製代碼
類對象定義本身的block屬性。函數
PDMineVC *vc = [[PDMineVC alloc] init];
vc.rebackBlock = ^(NSString *flag) {
NSLog(@"--%@",flag);
};
[self.navigationController pushViewController:vc animated:YES];
複製代碼
有兩種方式:值傳遞、指針傳遞oop
在聲明Block以後、調用Block以前,對局部變量進行修改。調用Block後,局部變量值不變。atom
int temp = 100;
// 聲明Block
void(^myBlock)() = ^{
NSLog(@"global = %d", temp);
};
temp = 101; // 修改變量的值
// 調用Block
myBlock();
// 調用後輸出"temp = 100"
複製代碼
解釋:聲明Block的時候,只是把變量的值
保存進Block代碼塊中,因此調用Block時,打印的仍然是變量原來的值。
引用block 外的變量,block 默認是將變量的
值
複製到其數據結構中來實現訪問的。
對於上一種狀況,只需用__block
修飾變量便可,只要變量值改變,值就跟着改變。
__block int temp = 100;
複製代碼
解釋:對於用 __block 修飾的外部變量引用,block 是複製其引用地址
來實現訪問的。
注意:
不能夠在Block中修改局部變量; 全局變量、static
靜態變量,在Block中的值也會隨修改而變。
#####3.保存一段代碼 在本類中定義Block,本類對象在另外一個類中調用Block。
#####4.block做爲函數的參數 把block當成方法的參數使用 在外界寫block的聲明,在方法內部調用block。 例子
方法的聲明
+(void)checkNetworkStatusOn:(void (^)(NSString * status))CallBack;
方法的定義
+(void)checkNetworkStatusOn:(void (^)(NSString * status))CallBack{
// ...
// blcok調用,傳遞信息
CallBack ? CallBack(@"網絡處於斷開狀態") : nil;
}
方法的調用,並聲明Block
[self checkNetworkStatusOn:^(NSString *status) {
NSLog(@"---->%@",status);
}];
複製代碼
// 定義帶參的block類型,本類對象調用,參數來自本類對象
typedef void(^selectedHandler)(NSUInteger index,NSString *title);
// 聲明方法,block做爲參數
- (instancetype)initWithFrame:(CGRect)frame
titles:(NSArray *)titles
selectedHandler:(selectedHandler)handler;
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titles selectedHandler:(selectedHandler)handler {
if ( [super initWithFrame:frame]) {
self.ablock = handler ; // 外界傳入代碼塊,外界來決定作什麼
}
return self;
}
複製代碼
複製代碼
若是對Block進行一次copy操做,那麼Block的內存會被移動到堆
中,這時須要開發人員對其進行內存管理。
在Block存儲在堆中時,若是在Block中引用了外面的對象,會該對象進行一次retain
操做。即便在Block自身調用了release
操做以後,不會release
該對象,這時會形成內存泄漏。
Person *pObject = [[Person alloc] init];
void(^myBlock)() = ^{
NSLog(@"------%@", pObject);
};
myBlock();
Block_copy(myBlock); // copy操做
// ...
Block_release(myBlock);
[pObject release];
// -->Person對象在這裏沒法正常被釋放,由於其在Block中被進行了一次retain操做。
複製代碼
爲了避免對所引用的對象進行一次retain
操做,可使用__block
來修飾對象
__block Person *pObject = [[Person alloc] init];
複製代碼
若是對象內部有一個Block屬性,而在Block內部又訪問了該對象,那麼會形成循環引用。 解決:
__block
修飾在對象的前面使用__block
來修飾,以免Block對對象進行retain
操做。 __block Person *p = [[Person alloc] init];
新建立一個弱指針來指向該對象,並將該弱指針放在Block中使用,這樣Block便不會形成循環引用。
__weak typeof(Person) weakP = p;
void(^myBlock)() = ^{
NSLog(@"------%@", weakP);
};
複製代碼
這樣雖然解決了循環引用,可是也容易涉及到另外一個問題: 由於Block是經過弱引用指向了Person對象,那麼有可能在調用Block以前,Person對象已經被釋放。因此咱們須要在Block內部
再定義一個強指針
來指向Person對象。
__weak typeof(Person) wp = p;
aBlock = ^(NSString *flag) {
__strong typeof(Person) sp = wp;
NSLog(@"%@", sp);
};
複製代碼
補充:
在ARC默認狀況下,Block的內存存儲在堆中,ARC會自動進行內存管理,程序員只須要避免循環引用便可。 在Block內部定義的變量,會在做用域結束時自動釋放,Block對其並無強引用關係,且在ARC中只須要避免循環引用便可,若是隻是Block單方面地對外部變量進行強引用,並不會形成內存泄漏。
www.jianshu.com/p/14efa33b3… * www.jianshu.com/p/649fca982… www.jianshu.com/p/45557fbef… www.jianshu.com/p/c389afedb… *