iOS 中 block 的使用

概念

代碼塊block是蘋果在iOS4開始引入的對C語言的擴展,用來實現匿名函數的特性,block是一種特殊的數據類型,其能夠正常定義變量、做爲參數、做爲返回值,特殊地,block還能夠保存一段代碼,在須要的時候調用,目前block已經普遍應用於iOS開發中,經常使用於GCD、動畫、排序及各種回調函數

定義與使用

block 變量的聲明

block 變量的聲明格式:返回值類型(^block名字)(參數列表);
    //聲明一個無返回值,兩個參數的 block
    void(^block1)(NSString *a,NSString *b);
    //省略寫法
    void(^block2)(NSString *,NSString *);

block變量的賦值

//block變量的賦值
    //block變量名 = ^(參數列表){函數體};
    block1 = ^(NSString *x,NSString *y){
        NSLog(@"%@--%@",x,y);
    };
    block1(@"123123",@"QWEQWEQWE");

聲明block變量的同時進行賦值

//聲明 block 變量的同時進行賦值
    int(^block3)(int) = ^(int a){
        return a*3;
    };
    NSLog(@"%d",block3(3));

使用typedef定義block類型

在實際使用Block的過程當中,咱們可能須要重複地聲明多個相同返回值相同參數列表的Block變量,若是老是重複地編寫一長串代碼來聲明變量會很是繁瑣,因此咱們可使用typedef來定義Block類型動畫

#pragma mark    使用 typedef 定義 block 類型
    //定義一個無返回值類型 無參數列表的 block
    typedef void (^Block4)();
    Block4 block4 = ^(){
        NSLog(@"i am block4");
    };
    block4();

block做爲函數參數

#pragma mark block做爲函數參數
    int(^block5)(int,int) = ^(int a,int b){
        return a+b;
    };
    [self useBlock5:block5];
    
    //簡化書寫
    //typedef int (^Block6)(int,int);(全局聲明)
    Block6 block6 = ^(int a,int b){
        return a+b;
    };
    [self useBlock6:block6];
    
    
- (void)useBlock5:(int(^)(int,int))block5 {
    NSLog(@"block5:%d",block5(3,5));
}
- (void)useBlock6:(Block6 )block6{
    NSLog(@"block6:%d",block6(4,5));
}

block內訪問局部變量

  • 在Block中能夠訪問局部變量
  • 在聲明Block以後、調用Block以前對局部變量進行修改,在調用Block時局部變量值是修改以前的舊值
  • 在Block中不能夠直接修改局部變量
#pragma mark block -----------訪問局部變量
    //block 中不能夠直接修改局部變量
    int value1 = 100;
    void (^block7)(void) = ^(){
           NSLog(@"value1:%d",value1);
    };
    value1 = 200;
    block7();//輸出100
  • 在局部變量前使用下劃線下劃線block修飾,在聲明Block以後、調用Block以前對局部變量進行修改,在調用Block時局部變量值是修改以後的新值
  • 在局部變量前使用下劃線下劃線block修飾,在Block中能夠直接修改局部變量
#pragma mark block -----------訪問局部變量
    //block 中不能夠直接修改局部變量
    //在局部變量前使用__block修飾,在Block中能夠直接修改局部變量
    __block int value1 = 100;
    void (^block7)(void) = ^(){
         value1++;
        NSLog(@"value1:%d",value1);
    };
    value1 = 200;
    block7();//輸出100 __block 修飾以後輸出200

block內訪問全局變量

  • 在聲明Block以後、調用Block以前對全局變量進行修改,在調用Block時全局變量值是修改以後的新值
#pragma mark ------------------block 訪問全局變量
    //在Block中能夠訪問全局變量
    value2 = 100;
    void(^block8)(void) = ^(){
        //在Block中能夠直接修改全局變量
        self->value2++;
        NSLog(@"value2:%d",self->value2);
    };
    value2 = 200;
    block8();

block內訪問靜態變量

#pragma mark --------block內訪問靜態變量
    static int value3 = 100;
    void(^block9)(void) = ^(){
        value3++;//在Block中能夠直接修改靜態變量
        NSLog(@"value3:%d",value3);
    };
    //在聲明Block以後、調用Block以前對靜態變量進行修改,在調用Block時靜態變量值是修改以後的新值
    value3 = 200;
    block9();

block 形成的循環引用問題

若是對象內部有一個Block屬性,而在Block內部又訪問了該對象,那麼會形成循環引用atom

狀況一指針

@interface Person : NSObject

@property (nonatomic, copy) void(^myBlock)();

@end


@implementation Person

- (void)dealloc
{
    NSLog(@"Person dealloc");
}

@end


Person *p = [[Person alloc] init];
        
p.myBlock = ^{
    NSLog(@"------%@", p);
};
p.myBlock();
        
// 由於myBlock做爲Person的屬性,採用copy修飾符修飾(這樣才能保證Block在堆裏面,以避免Block在棧中被系統釋放),因此Block會對Person對象進行一次強引用,致使循環引用沒法釋放

狀況二code

@interface Person : NSObject

@property (nonatomic, copy) void(^myBlock)();

- (void)resetBlock;

@end


@implementation Person

- (void)resetBlock
{
    self.myBlock = ^{
        NSLog(@"------%@", self);
    };
}

- (void)dealloc
{
    NSLog(@"Person dealloc");
}

@end


Person *p = [[Person alloc] init];
[p resetBlock];

// Person對象在這裏沒法正常釋放,在resetBlock方法實現中,Block內部對self進行了一次強引用,致使循環引用沒法釋放

解決循環引用的辦法是使用一個弱引用的指針指向該對象,而後在Block內部使用該弱引用指針來進行操做,這樣避免了Block對對象進行強引用對象

狀況一排序

@interface Person : NSObject

@property (nonatomic, copy) void(^myBlock)();

@end


@implementation Person

- (void)dealloc
{
    NSLog(@"Person dealloc");
}

@end


Person *p = [[Person alloc] init];
__weak typeof(p) weakP = p;

p.myBlock = ^{
    NSLog(@"------%@", weakP);
};
p.myBlock();
        
// Person對象在這裏能夠正常被釋放

狀況二開發

@interface Person : NSObject

@property (nonatomic, copy) void(^myBlock)();

- (void)resetBlock;

@end


@implementation Person

- (void)resetBlock
{
    // 這裏爲了通用一點,可使用__weak typeof(self) weakP = self;
    __weak Person *weakP = self;
    self.myBlock = ^{
        NSLog(@"------%@", weakP);
    };
}

- (void)dealloc
{
    NSLog(@"Person dealloc");
}

@end


Person *p = [[Person alloc] init];
[p resetBlock];

// Person對象在這裏能夠正常被釋放
相關文章
相關標籤/搜索