iOS底层知识技术iOS底层基础知识

iOS block和delegate的区别

2017-08-24  本文已影响1872人  豆丶浆油条

  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当做一个成员变量、属性、参数使用,使用起来非常灵活。像用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的性能,提高流畅性,从点滴做起。

上一篇下一篇

猜你喜欢

热点阅读