iOS block和代理的区别

  这里主要是把block和代理作为回调的两种方式,在应用场景上进行比较。block和代理本质上是不同的,因为block其实是一个对象,代理是一种设计模式(委托-代理模式)。

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.代理简介

  在为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。摘自百度百科
  代理是一种通用设计模式,很多语言上都有实现。在iOS中,代理作为一种消息传递方式,使用的非常普遍。代理包括三部分:代理,委托,协议。代理方通过实现协议里的方法,接收委托方传递过来的消息。

3.block的优势

  block的代码可读性更好。因为block只要实现就可以了,而代理需要遵守协议并且实现协议里的方法,而两者还不在一个地方。代理使用起来也更麻烦,因为要声明协议、声明代理属性、遵守协议、实现协议里的方法。block不需要声明,也不需要遵守,只需要声明属性和实现就可以了。
  block是一种轻量级的回调,可以直接访问上下文,由于block的代码是内联的,运行效率更高。block就是一个对象,实现了匿名函数的功能。所以我们可以把block当做一个成员变量、属性、参数使用,使用起来非常灵活。像用AFNetworking请求数据和GCD实现多线程,都使用了block回调。

4.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

5.如何使用

  优先使用block。
  如果回调的状态很多,多于三个使用代理。
  如果回调的很频繁,次数很多,像UITableview,每次初始化、滑动、点击都会回调,使用代理。
  block和代理都各有优缺点,所以我们一定要理解区分使用场景,应用适合的回调方式。优化APP的性能,提高流畅性,从点滴做起。

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 7,217评论 1 23
  • 理论知识点 NotificationCenter 通知中心:“一对多”,在APP中,很多控制器都需要知道一个事件,...
    朝雨晚风阅读 3,532评论 3 11
  • 基础 1. 为什么说Objective-C是一门动态的语言? 2. 讲一下MVC和MVVM,MVP? 3. 为...
    波妞和酱豆子阅读 2,781评论 0 47
  • 夜晚的雨只有在路灯下才能看清,夜晚的风只有沾上雨才能察觉,整条街会只有你一个人,就像电影一样,孤独的人深夜有雨陪伴...
    太七的猫阅读 35评论 0 2
  • 年轻可以挥霍身体,殊不知到老了,没有好身体多受罪! 在这件事情上我常常跟老公发生冲突,他是无肉不欢,还常常给女儿买...
    灿然加一新阅读 54评论 0 2