ios中block的基本瞭解和使用

簡介

Block是將函數及其執行上下文封裝起來的對象。能夠保存一段代碼,在須要的時候調用。javascript

聲明

格式爲: 返回值類型(^Block名字)(參數列表); 如:java

// 無參無返回
void (^aBlock)(void);

// 無參有返回
int(^aBlock)(void) ;

// 有參有返回
NSString* (^aBlock)(NSString * x, int y);

// 無參有返回
NSString* (^aBlock)(void);
複製代碼
  • block屬性,使用copy修飾,最好不用strong。
@property(nonatomic,copy)NSString* (^ablock)(void);
複製代碼
  • 自定義Block類型
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.傳遞數據(把數據傳遞出去、逆傳)異步

  • 在本身的.h中,聲明帶參數的block屬性。
@interface PDMineVC : PDViewController

@property(nonatomic,copy)void (^rebackBlock)(NSString *flag);

@end
複製代碼
  • 在.m中,調用block。
// 調用,把須要傳遞的信息 做爲參數
self.rebackBlock(@"425");
複製代碼
  • 在外界

類對象定義本身的block屬性。函數

PDMineVC *vc = [[PDMineVC alloc] init];
vc.rebackBlock = ^(NSString *flag) {
    NSLog(@"--%@",flag);
};
[self.navigationController pushViewController:vc animated:YES];
複製代碼
2.捕獲變量

有兩種方式:值傳遞、指針傳遞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;
}

複製代碼
5.block做爲函數的返回值(少用)
複製代碼

block內存管理

若是對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來修飾,以免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… *

相關文章
相關標籤/搜索