本文中分析兩個問題:
1. Block閉包是一個引用類型
2. Block捕獲外部變量
1、Block結構
1.1 IR文件分析
獲取IR文件:swiftc -emit-ir 文件地址/main.swift > ./main.ll
func makeIncrementer() -> () -> Int{
var runningTotal = 10
//內嵌函數,也是一個閉包
func incrementer() -> Int{
runningTotal += 1
return runningTotal
}
return incrementer
}
IR文件:
- 可以看到使用
swift_allocObject
來分配堆內存
,間接證明Block是引用類型
. - 但是不是很直觀。
1.2 結構圖
1.3 代碼結構
一個外部變量:
struct FuntionData<T>{
var ptr: UnsafeRawPointer
var captureValue: UnsafePointer<Box<T>>
}
struct Box<T> {
var refCounted: HeapObject
var value: UnsafePointer<Box<T>>
}
struct HeapObject{
var type: UnsafeRawPointer
var refCount: UInt64
}
2、 Block結構仿寫
一個外部變量時
struct FuntionData<T>{
var ptr: UnsafeRawPointer
var captureValue: UnsafePointer<Box<T>>
}
struct Box<T> {
var refCounted: HeapObject
var value: UnsafePointer<Box<T>>
}
struct HeapObject{
var type: UnsafeRawPointer
var refCount: UInt64
}
//閉包的結構體,方便獲取閉包地址
struct VoidIntFun {
var f: () ->Int
}
func makeIncrementer() -> () -> Int{
var runningTotal = 10
//內嵌函數,也是一個閉包
func incrementer() -> Int{
runningTotal += 1
return runningTotal
}
return incrementer
}
let makeInc = VoidIntFun(f: makeIncrementer())
let ptr = UnsafeMutablePointer<VoidIntFun>.allocate(capacity: 1)
//初始化的內存空間
ptr.initialize(to: makeInc)
//將ptr重新綁定內存
let ctx = ptr.withMemoryRebound(to: FunctionData<Box<Int>>.self, capacity: 1) { $0.pointee }
print(ctx.ptr)
print(ctx.captureValue.pointee)
輸出:
- 不論外部變量是是否發生修改,都將包裝成一個
Box<T>
的結構體
二個外部變量時
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 12
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
輸出:
- 如果是兩個變量,其中
變量二
發生了修改(相當于OC中的__block
),會包裝成對象并存到捕獲列表
;
如果是這樣:
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 12
func incrementer() -> Int {
return runningTotal + amount
}
return incrementer
}
輸出:
- 如果沒有發生變化,就直接引用
值
,并不會進行引用類型的包裝;
總結
- 引用單個變量時,不論當前變量在Block是否發生了變化,都會被包裝成對象,存在
captureValue捕獲列表里
- 多個變量時:
-
發生變化的外部變量進行對象包裝,然后將指針地址存在捕獲列表里
. -
沒有修改的變量就會直接保存變量的值
;
-
- 相比之下Swift中的Block捕獲方式更加簡潔,但是對編譯器的要求就會更高;