內存管理
- Swift采用引用計數的ARC內存管理方案(堆空間)
- Swift的ARC中有3鐘引用
- 強引用
- 弱引用(weak reference)
- 必須是可先類型的var,因為實例銷毀后,ARC會自動弱引用設置為nil
- ARC自動給弱引用設置nil時。不會觸發屬性觀察器
- 無主引用(unowned reference)
- 不會產生強引用,實例銷毀后仍然存儲著實例的內存地址(類似于OC中的unsafe_unretained)
- 在實例銷毀后訪問無主引用,會產生運行時錯誤(野指針)
循環引用
- weak, unowned都能解決循環引用問題,unowned要比weak少一些性能消耗
- 在生命周期可能會變為nil的使用weak
- 初始化后再也不會變為nil的使用unowned
閉包的循環引用
- 閉包表達式默認會對用到的外層對象產生額外的強引用,在閉包表達式的捕獲變量聲明weak或unowned引用,解決循環引用問題
@escaping逃逸閉包
- 逃逸閉包:閉包有可能在函數結束后調用,閉包調用逃離了函數的作用域,需要通過
@escaping
聲明
- 非逃逸閉包:閉包調用發生在函數結束前,閉包調用在函數作用域內
// fn是非逃逸閉包
func test1(_ fn: Fn) { fn() }
// fn是逃逸閉包
var gFn: Fn?
func test2(_ fn: @escaping Fn) { gFn = fn }
// fn是逃逸閉包
func test3(_ fn: @escaping Fn) {
DispatchQueue.global().async {
fn()
}
}
class Person {
var fn: Fn
// fn是逃逸閉包
init(fn: @escaping Fn) {
self.fn = fn
}
func run() {
// DispatchQueue.global().async也是一個逃逸閉包
// 它用到了實例成員(屬性、方法),編譯器會強制要求明確寫出self
DispatchQueue.global().async {
self.fn()
}
}
}
typealias Fn = () -> ()
func other1(_ fn: Fn) { fn() }
func other2(_ fn: @escaping Fn) { fn() }
func test(value: inout Int) -> Fn {
other1 { value += 1 }
// error: 逃逸閉包不能捕獲inout參數
other2 { value += 1 }
func plus() { value += 1 }
// error: 逃逸閉包不能捕獲inout參數
return plus
}
指針
- UnsafePointer<Pointee> 類似于 const Pointee *
- UnsafeMutablePointer<Pointee> 類似于 Pointee *
- UnsafeRawPointer 類似于 const void *
- UnsafeMutableRawPointer 類似于 void *
var age = 10
func test1(_ ptr: UnsafeMutablePointer<Int>) {
ptr.pointee += 10
}
func test2(_ ptr: UnsafePointer<Int>) {
// ptr.pointee += 10 錯誤
print(ptr.pointee)
}
func test3(_ ptr: UnsafeMutableRawPointer) {
ptr.storeBytes(of: 20, as: Int.self)
}
func test4(_ ptr: UnsafeRawPointer) {
// ptr.storeBytes(of: 20, as: Int.self) 錯誤
print(ptr.load(as: Int.self))
}
獲得指向某個變量的指針
var age = 11
var ptr1 = withUnsafeMutablePointer(to: &age ) { $0 }
var ptr2 = withUnsafePointer(to: &age, { $0 })
ptr1.pointee = 22
print(ptr2.pointee) // 22
print(age) // 22
var ptr3 = withUnsafeMutablePointer(to: &age, { UnsafeMutableRawPointer($0) })
var ptr4 = withUnsafePointer(to: age, { UnsafeRawPointer($0) })
ptr3.storeBytes(of: 33, as: Int.self) // 33
print(age) // 3
獲得指向堆空實例的指針
class Person {}
var person = Person()
var ptr5 = withUnsafePointer(to: &person) { UnsafeRawPointer($0) }
var heapPtr = UnsafeRawPointer(bitPattern: ptr5.load(as: UInt.self))
print(heapPtr)
創建指針
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
ptr.storeBytes(of: 11, as: Int.self)
ptr.advanced(by: 8).storeBytes(of: 22, as: Int.self)
print(ptr.load(as: Int.self)) // 11
print(ptr.advanced(by: 8).load(as: Int.self)) // 22
ptr.deallocate()
do {
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)
ptr.initialize(to: 11)
ptr.successor().initialize(to: 22)
ptr.successor().successor().initialize(to: 33)
print(ptr.pointee) // 11
print((ptr + 1).pointee) // 22
print((ptr + 2).pointee) // 33
print(ptr[0]) // 11
print(ptr[1]) // 22
print(ptr[2]) // 33
ptr.deinitialize(count: 3)
ptr.deallocate()
}
do {
class Person {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
deinit { print(name, "deinit") }
}
var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
ptr.initialize(to: Person(age: 10, name: "Jack"))
(ptr + 1).initialize(to: Person(age: 11, name: "Rose"))
(ptr + 2).initialize(to: Person(age: 12, name: "Kate"))
// Jack deinit
// Rose deinit
// Kate deinit
ptr.deinitialize(count: 3)
ptr.deallocate()
}