Objective-C 中的 Block

Block是一種蘋果開發(fā)的基于C的調(diào)用方式, 從iOS 4.0引入之后, 似乎就受到了Apple的特殊照顧和開發(fā)者的喜愛. 在如今的開發(fā)中, Block雖然有不足的地方, 但也依然被廣泛的使用. 從字面意思來看, Block就是塊, 也就是有某種功能的代碼段. 本文主要介紹的Block的基本用法, 同時談?wù)凚lock與Delegation各自的優(yōu)劣.

一.Block基本語法

BOOL (^isInputEven)(int) = ^(int input) {
        if (input % 2 == 0) {
            return YES;
        } else {
            return NO;
        }
    };

這是一個很簡單的Block, 對比C語言的函數(shù)是不是感覺很相似, BOOL為這個Block的返回值, ^后的isInputEven為Block的函數(shù)名, int為該block接受的參數(shù)類型, =后面的int intPut是對這個參數(shù)的描述, 在這個block中input用來指代傳入的參數(shù). 剛開始使用Block時, 應(yīng)該都會為這個語法頭疼.但是習慣之后發(fā)現(xiàn)其實就是平時我們用的方法的另一種寫法.

  • 想用使用這個Block也很簡單, 就如C語言函數(shù).
    isInputEven(5);
    NSLog(@"%@", isInputEven(5) ? @"is Even" : @"is not even");

  • Block的幾種形式
    // 有參有返回值
    int (^sum)(int, int) = ^(int a, int b) {
        return a + b;
    };
    // 無參無返回
    void (^noParameterOrReturnValue)(void) = ^(void) {
        
    };
    // 無參無返回也可直接寫為
    void (^block)() = ^{
        
    };
    // 有參無返回值
    void (^handleNumber)(int number) = ^(int number) {
        
    };
    // 無參有返回
    NSString *(^returnString)() = ^ {
        return @"無參有返回值";
    };

二.Block的使用

  • block作為屬性使用

viewController中push到SecondViewController, 第二個VC通過點擊導航按鈕返回, 把secondViewControllertitle賦值給viewControllerlabel. 這是很常見的從后往前傳值, 一般遇到這種情況, 我們經(jīng)常都使用協(xié)議傳值, 而Block的使用就比Delegation方便了很多.

首先在SecondViewController.h中聲明Block屬性, 可以把 void(^)(NSString *)看作類型, secondVCTitle則為屬性名.

@interface SecondViewController : UIViewController
@property (nonatomic, copy) void (^secondVCTitle)(NSString *title);
@end

SecondViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"Second";
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(backToVC:)];
}

- (void)backToVC:(UIBarButtonItem *)barButtonItem {
    // secondViewController返回之前設(shè)置block要傳的值
    self.secondVCTitle(self.title);
    [self.navigationController popViewControllerAnimated:YES];
}

viewController中button的點擊方法

- (IBAction)pushToSecondVC:(id)sender {
    SecondViewController *secondVC = [[SecondViewController alloc] init];
    secondVC.secondVCTitle = ^(NSString *title) {
        // 接收block傳過來的值
        _titleLabel.text = title;
    };
    [self.navigationController pushViewController:secondVC animated:YES];
}

這樣很簡單的幾步就把后一個VC的值傳了過來, 是不是比Delegation簡單了很多.

  • block作為方法參數(shù)使用

下面以一個自定義view為例

#import <UIKit/UIKit.h>

@interface CusView : UIView
// block作為方法參數(shù)
- (void)playButton:(void (^)(UIButton *play))playButton;
@end

cusView中只創(chuàng)建了一個button控件, 在.m中實現(xiàn)playButton:方法, 需要一個block屬性

#import "CusView.h"

@interface CusView ()
@property (nonatomic, strong) UIButton *playButton;
// 帶一個參數(shù)的block屬性
@property (nonatomic, copy) void (^playBut)(UIButton * play);
@end

@implementation CusView

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _playButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _playButton.backgroundColor = [UIColor yellowColor];
        [_playButton addTarget:self action:@selector(playButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_playButton];
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    _playButton.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
}
// 帶block參數(shù)的方法
- (void)playButton:(void (^)(UIButton *))playButton {
    self.playBut = playButton;
}

- (void)playButtonClicked:(UIButton *)playButton {
    self.playBut(playButton);
}
@end

ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
// 創(chuàng)建cusView
    CusView *cusView = [[CusView alloc] initWithFrame:CGRectMake(0, 64, 50, 50)];
    [self.view addSubview:cusView];
// 調(diào)用playButton方法
    [cusView playButton:^(UIButton *play) {
        NSLog(@"點擊了playButton");
    }];
}

三. Block相關(guān)的修飾符

  • __block
  • __weak
  • __strong

__block

  • 當我們想要在block中修改a的值, 估計會這樣寫, 但實際上block只能訪問局部變量, 得到的只是該變量的副本, 修改之后也不會影響原來的值.
// wrong
    int a = 0;
    void (^blockTest)() = ^{
        a = 100;
    };
  • 想要修改a的值 則需要加上__block修飾
    __block int a = 0;
    void (^blockTest)() = ^{
        a = 100;
    };
  • __block在MRC環(huán)境下還有一個作用, 能防止block對內(nèi)部的對象進行強引用, 也就是防止循環(huán)引用.

__weak

__weak弱引用, 用__weak修飾變量, 當變量消失時, 會自動把對象置空, 可以防止循環(huán)引用(只作用在ARC環(huán)境).

__strong

__strong強引用:strong和retain相似,只要有一個strong指針指向?qū)ο?,該對象就不會被銷毀. 在ARC環(huán)境下, 雖然沒有顯示的聲明,但是Objective-C默認聲明的一個對象就為 __strong.

// 兩者等價
id object = [[NSObject alloc] init];
id __strong object = [[NSObject alloc] init];

四.Block與Delegation

  • Delegation的優(yōu)點: 通常被weak引用, 不會出現(xiàn)內(nèi)存泄漏問題, 可以將一類功能的方法結(jié)合在一起.需要在兩個界面間傳遞的信息比較多時, 使用起來比block更好.
    缺點: 應(yīng)該是代碼比較多, 比較麻煩.

  • Block的優(yōu)點: 簡化代碼,增強代碼可讀性, 不需要代理人來傳遞, 可以用作參數(shù)傳遞.
    缺點: 如果block需要多次調(diào)用, 會有各種循環(huán)引用的問題.

如有不足之處, 還望各位指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Apple從OS X 10.4和iOS 4以后開始支持block,相對于delegate,block有很多便捷之處...
    HK_Hank閱讀 12,871評論 1 46
  • 原文地址:Objective-C中的Block 1.相關(guān)概念 在這篇筆記開始之前,我們需要對以下概念有所了解。 1...
    默默_David閱讀 463評論 0 1
  • .相關(guān)概念 在這篇筆記開始之前,我們需要對以下概念有所了解。 1.1 操作系統(tǒng)中的棧和堆 注:這里所說的堆和棧與數(shù)...
    狼鳳皇閱讀 533評論 0 0
  • 1.相關(guān)概念 在這篇筆記開始之前,我們需要對以下概念有所了解。 1.1 操作系統(tǒng)中的棧和堆 注:這里所說的堆和棧與...
    DevTalking閱讀 3,798評論 3 76
  • 演繹法 第二天,我們依他的安排碰面,一起到貝克街221B號看房。臥房舒適宜人,會客室寬敞通風。裝修風格明快,兩大扇...
    史黛拉945閱讀 465評論 0 1

友情鏈接更多精彩內(nèi)容