1. 程式人生 > >iOS中Block的基礎用法

iOS中Block的基礎用法

本文簡介

本章不會對Block做過多的實現研究。只是講解基本的用法。純粹基礎知識。結合實際專案怎麼去做舉例。Block使用場景,可以在兩個介面的傳值,也可以對程式碼封裝作為引數的傳遞等。用過GCD就知道Block的精妙之處。

Block簡介

Block是一種比較特殊的資料型別。它可以儲存一段程式碼,在合適的時候取出來呼叫。

Block的修飾

ARC情況下
1.如果用copy修飾Block,該Block就會儲存在堆空間。則會對Block的內部物件進行強引用,導致迴圈引用。記憶體無法釋放。
解決方法:
新建一個指標(__weak typeof(Target) weakTarget = Target )指向Block程式碼塊裡的物件,然後用weakTarget進行操作。就可以解決迴圈引用問題。

2.如果用weak修飾Block,該Block就會存放在棧空間。不會出現迴圈引用問題。

MRC情況下
用copy修飾後,如果要在Block內部使用物件,則需要進行(__block typeof(Target) blockTarget = Target )處理。在Block裡面用blockTarget進行操作。

Block的定義格式

返回值型別(^block變數名)(形參列表) = ^(形參列表) {
};
呼叫Block儲存的程式碼
block變數名(實參);

預設情況下,Block內部不能修改外面的區域性變數
Block內部可以修改使用__block修飾的區域性變數

Block的模式

1.無引數無返回值的Block
2.有引數無返回值的Block
3.有引數有返回值的Block

Block簡單用法舉例

無引數無返回值的Block

/**
 *  無引數無返回值的Block
 */
-(void)func1{
    /**
     *  void :就是無返回值
     *  emptyBlock:就是該block的名字
     *  ():這裡相當於放參數。由於這裡是無引數,所以就什麼都不寫
     */
    void (^emptyBlock)() = ^(){
        NSLog(@"無引數,無返回值的Block");
    };
    emptyBlock();
}

有引數無返回值的Block

/**
     *  呼叫這個block進行兩個引數相加
     *
     *  @param int 引數A
     *  @param int 引數B
     *
     *  @return 無返回值
     */
    void (^sumBlock)(int ,int ) = ^(int a,int b){
        NSLog(@"%d + %d = %d",a,b,a+b);
    };
    /**
     *  呼叫這個sumBlock的Block,得到的結果是20
     */
    sumBlock(10,10);

有引數有返回值的Block

/**
     *  有引數有返回值
     *
     *  @param NSString 字串1
     *  @param NSString 字串2
     *
     *  @return 返回拼接好的字串3
     */    
    NSString* (^logBlock)(NSString *,NSString *) = ^(NSString * str1,NSString *str2){
        return [NSString stringWithFormat:@"%@%@",str1,str2];
    };
    //呼叫logBlock,輸出的是 我是Block
    NSLog(@"%@", logBlock(@"我是",@"Block"));
Block結合typedef使用

自己定義一個Block型別,用定義的型別去建立Block,更加簡單便捷。
這裡舉例一個Block回撥修改上一下介面的背景顏色。
ViewController1 控制器1,ViewController2 控制器2
控制器1跳轉到控制器2,然後在控制器2觸發事件回撥修改控制器1的背景顏色為紅色。

ViewController2的實現

#import <UIKit/UIKit.h>
@interface ViewController2 : UIViewController
/**
 *  定義了一個changeColor的Block。這個changeColor必須帶一個引數,這個引數的型別必須為id型別的
 *  無返回值
 *  @param id
 */
typedef void(^changeColor)(id);
/**
 *  用上面定義的changeColor宣告一個Block,宣告的這個Block必須遵守宣告的要求。
 */
@property (nonatomic, copy) changeColor backgroundColor;
@end
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //宣告一個顏色
    UIColor *color = [UIColor redColor];
    //用剛剛宣告的那個Block去回撥修改上一介面的背景色
    self.backgroundColor(color);
}

ViewController1的實現

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    ViewController2 *vc =[[ViewController2 alloc]init];
    // 回撥修改顏色
    vc.backgroundColor = ^(UIColor *color){
        self.view.backgroundColor = color;
    };
    [self.navigationController pushViewController:vc animated:YES];
}