iOS block和代理的區別

  block和代理是iOS開發中實現回調的兩種方式,大多數情況下是用哪個都可以,主要看個人喜好。本文主要是對兩者做一下對比。

1.block簡介

  在 iOS中, block一共分三種。
  (1)全局靜態 block,不會訪問任何外部變量,執行完就銷燬。

 ^{
        NSLog(@"Hello World!");
    }();

  (2)保存在棧中的 block,當函數返回時會被銷燬,和第一種的區別就是調用了外部變量。

 
    [UIView animateWithDuration:3 animations:^{
       
        self.view.backgroundColor = [UIColor redColor];
    }];

  (3)保存在堆中的 block,當引用計數爲 0 時會被銷燬。例如按鈕的點擊事件,一直存在,即使執行過,也不銷燬,因爲按鈕還可能被點擊,持有按鈕的View被銷燬,它纔會被銷燬。

#import <UIKit/UIKit.h>

typedef void(^ButtonClickBlcok)();

@interface TestView : UIView

@property (nonatomic, copy) ButtonClickBlcok buttonClickBlcok;

@end
#import "TestView.h"

@implementation TestView

- (IBAction)buttonClick:(id)sender {
    
    if (self.buttonClickBlcok) {
        self.buttonClickBlcok();
    }
}
@end

2.block優點

  block的代碼可讀性更好。因爲應用block和實現block的地方在一起。代理的聲明和實現就分開來了,在兩個類中。代理使用起來也更麻煩,因爲要聲明協議、聲明代理、遵守協議、實現協議裏的方法。block不需要聲明,也不需要遵守,只需要聲明和實現就可以了。
  block是一種輕量級的回調,可以直接訪問上下文,由於block的代碼是內聯的,運行效率更高。block就是一個對象,實現了匿名函數的功能。所以我們可以把block當做一個成員變量、屬性、參數使用,使用起來非常靈活。像用AFNetworking請求數據和GCD實現多線程,都使用了block回調。

3.block缺點

  blcok的運行成本高。block出棧需要將使用的數據從棧內存拷貝到堆內存,當然對象的話就是引用計數加1,使用完或者block置nil後才銷燬。delegate只是保存了一個對象指針(一定要用week修飾delegate,不然也會循環引用),直接回調,沒有額外消耗。就像C的函數指針,只多做了一個查表動作。
  block容易造成循環引用,而且不易察覺。因爲爲了blcok不被系統回收,所以我們都用copy關鍵字修飾,實行強引用。block對捕獲的變量也都是強引用,所以就會造成循環引用。

#import "ViewController.h"

typedef void(^TestBlock)(void);

@interface ViewController ()
{
    void (^_testCycleBlock)(void);
}
@end

@implementation ViewController

- (void)viewDidLoad {
  
    [super viewDidLoad];
    
    __weak ViewController *weakSelf = self;
    _testCycleBlock = ^{

        /**
          //引發循環引用
          NSLog(@"%@", self);
         */
        //防止循環引用
        NSLog(@"%@", weakSelf);
    };
}
@end

4.如何使用

  優先使用block。
  如果回調函數很多,多餘三個使用代理。
  如果回調的很頻繁,次數很多,像UITableview,每次初始化、滑動、點擊都會回調,使用代理。
  block和代理都各有優缺點,所以我們一定要理解區分使用場景,應用適合的回調方式。優化APP的性能,提高流暢性,從點滴做起。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章