返回

在底层的世界里徜徉:揭秘 Block 的奥秘(上)

IOS

iOS 底层原理:Block 分析(上)

踏入 iOS 开发的广袤世界,我们常会遭遇一个神秘而强大的存在——Block。它是代码中的一颗璀璨明珠,在各种场景下大显神通,但它的底层原理却往往令人难以捉摸。本篇文章将带你开启一段探险之旅,深入剖析 Block 的类型、循环引用,以及一些常见的面试题。

一、Block 的类型

Block 是一种在编译时创建的闭包,用于捕获一个函数以及该函数所引用的变量。它具有以下两种类型:

1. GlobalBlock

位于全局区,在 Block 内部不使用任何外部变量。这意味着它在整个程序的生命周期内都存在,并且不会造成循环引用。

2. StackBlock

位于栈区,在 Block 内部使用了外部变量。它与所引用的变量的生命周期相关,因此需要小心处理,避免造成循环引用。

二、循环引用

循环引用是指两个或多个对象互相持有强引用,导致内存泄漏。在 Block 中,循环引用可能发生在 StackBlock 捕获了外部变量时。

1. 造成循环引用

// 造成循环引用
__block id strongObject;
id block = ^{
    return strongObject;
};

在以上示例中,Block 捕获了对 strongObject 的强引用,而 strongObject 又持有对 Block 的强引用。这形成了一个循环引用,导致这两个对象无法被释放。

2. 避免循环引用

要避免循环引用,可以在 Block 内部使用弱引用(__weak)或无主引用(__unsafe_unretained)来捕获外部变量。

// 避免循环引用
__weak id weakObject;
id block = ^{
    return weakObject;
};

三、面试题

1. Block 是什么?它如何工作?

Block 是一种闭包,可以捕获一个函数以及它所引用的变量。当 Block 被调用时,它将执行捕获的函数并返回结果。

2. Block 有哪些类型?它们有什么区别?

Block 有两种类型:GlobalBlock 和 StackBlock。GlobalBlock 不使用外部变量,StackBlock 使用外部变量。GlobalBlock 不会造成循环引用,StackBlock 可能造成循环引用。

3. 如何避免 Block 中的循环引用?

在 Block 内部使用弱引用(__weak)或无主引用(__unsafe_unretained)来捕获外部变量。

结语

Block 是 iOS 开发中一个强大的工具,但它也带来了循环引用等问题。通过深入理解 Block 的类型和循环引用,我们可以避免这些问题,并更有效地利用 Block 的强大功能。在下一篇文章中,我们将通过源码分析进一步验证这些上层表现。