Objective-C 中的 Block

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

一.Block基本語法

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

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

  • 想用使用這個(gè)Block也很簡(jiǎn)單, 就如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, 第二個(gè)VC通過點(diǎn)擊導(dǎo)航按鈕返回, 把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的點(diǎn)擊方法

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

這樣很簡(jiǎn)單的幾步就把后一個(gè)VC的值傳了過來, 是不是比Delegation簡(jiǎn)單了很多.

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

下面以一個(gè)自定義view為例

#import <UIKit/UIKit.h>

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

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

#import "CusView.h"

@interface CusView ()
@property (nonatomic, strong) UIButton *playButton;
// 帶一個(gè)參數(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(@"點(diǎn)擊了playButton");
    }];
}

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

  • __block
  • __weak
  • __strong

__block

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

__weak

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

__strong

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

// 兩者等價(jià)
id object = [[NSObject alloc] init];
id __strong object = [[NSObject alloc] init];

四.Block與Delegation

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末千扔,一起剝皮案震驚了整個(gè)濱河市慧库,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溅呢,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異榛臼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)窜司,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門沛善,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人塞祈,你說我怎么就攤上這事金刁。” “怎么了议薪?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵尤蛮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我斯议,道長(zhǎng)产捞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任哼御,我火速辦了婚禮坯临,結(jié)果婚禮上焊唬,老公的妹妹穿的比我還像新娘。我一直安慰自己看靠,他們只是感情好赶促,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衷笋,像睡著了一般芳杏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辟宗,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天爵赵,我揣著相機(jī)與錄音,去河邊找鬼泊脐。 笑死空幻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的容客。 我是一名探鬼主播秕铛,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼缩挑!你這毒婦竟也來了但两?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤供置,失蹤者是張志新(化名)和其女友劉穎谨湘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芥丧,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡紧阔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了续担。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擅耽。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖物遇,靈堂內(nèi)的尸體忽然破棺而出乖仇,到底是詐尸還是另有隱情,我是刑警寧澤挎挖,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布这敬,位于F島的核電站,受9級(jí)特大地震影響蕉朵,放射性物質(zhì)發(fā)生泄漏崔涂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一始衅、第九天 我趴在偏房一處隱蔽的房頂上張望冷蚂。 院中可真熱鬧缭保,春花似錦、人聲如沸蝙茶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隆夯。三九已至钳恕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹄衷,已是汗流浹背忧额。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愧口,地道東北人睦番。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像耍属,于是被迫代替她去往敵國(guó)和親托嚣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Apple從OS X 10.4和iOS 4以后開始支持block厚骗,相對(duì)于delegate示启,block有很多便捷之處...
    HK_Hank閱讀 12,383評(píng)論 1 46
  • 原文地址:Objective-C中的Block 1.相關(guān)概念 在這篇筆記開始之前,我們需要對(duì)以下概念有所了解领舰。 1...
    默默_David閱讀 405評(píng)論 0 1
  • .相關(guān)概念 在這篇筆記開始之前丑搔,我們需要對(duì)以下概念有所了解。 1.1 操作系統(tǒng)中的棧和堆 注:這里所說的堆和棧與數(shù)...
    狼鳳皇閱讀 482評(píng)論 0 0
  • 1.相關(guān)概念 在這篇筆記開始之前提揍,我們需要對(duì)以下概念有所了解。 1.1 操作系統(tǒng)中的棧和堆 注:這里所說的堆和棧與...
    DevTalking閱讀 3,723評(píng)論 3 76
  • 演繹法 第二天煮仇,我們依他的安排碰面劳跃,一起到貝克街221B號(hào)看房。臥房舒適宜人浙垫,會(huì)客室寬敞通風(fēng)刨仑。裝修風(fēng)格明快,兩大扇...
    史黛拉945閱讀 396評(píng)論 0 1