指針不是安全的
1.野指針。指針指向?qū)ο筢尫牛羔樧優(yōu)橐爸羔?/p>
2.指針超出內(nèi)存空間邊界訪問。如數(shù)組越界
3.原?指針和類型指針的轉(zhuǎn)換,會(huì)有數(shù)據(jù)丟失
指針類型
Swift中的指針分為兩類,
類型指針: typed pointer 指定數(shù)據(jù)類型指針,
原?指針: raw pointer 未指定數(shù)據(jù)類型的指針
原生指針
1.創(chuàng)建UnsafeMutableRawPointer.allocate
2.銷毀指針deallocate()
3.儲(chǔ)存值storeBytes(of: i, as:?Int.self)
4.讀取值load(fromByteOffset: i?*?MemoryLayout<Int>.stride, as:?Int.self)
3.移動(dòng)指針advanced(by: i?*?MemoryLayout<Int>.stride)
func demo1() {
? ? ? let p = UnsafeMutableRawPointer.allocate(byteCount: 4 * 8, alignment: 8)
? ? ? defer {
?? ? ? ? print("32")
?? ? ? ? p.deallocate()
? ? ? }
?? ? ?
? ? ? for i in 0..<4 {
?? ? ? ? p.advanced(by: i * MemoryLayout<Int>.stride).storeBytes(of: i, as: Int.self)
? ? ? }
? ? ? print(p)
? ? ? for i in 0..<4 {
?? ? ? ? let value = p.load(fromByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)
?? ? ? ? print(value)
? ? ? }
?? }
類型指針
第?種?式就是直接分配內(nèi)存?
1.創(chuàng)建UnsafeMutablePointer<LGPerson>.allocate
2.銷毀??p.deinitialize(count:?5) ->??p.deallocate()
3.儲(chǔ)存值p[0] ?= ...
4.讀取值?pointee屬性
let p = UnsafeMutablePointer<LGPerson>.allocate(capacity: 5)
? ? ? defer {
?? ? ? ? p.deinitialize(count: 5)
?? ? ? ? p.deallocate()
? ? ? }
? ? ? p[0] = LGPerson(age: 18, sex: true, married: true)
? ? ? p[1] = LGPerson(age: 19, sex: true, married: true)
? ? ? print(p)
? ? ? print(p.pointee)
第二種方式
通過已有變量獲取?
通過withUnsafePointer(to: &age) { $0.pointee?+?21} 獲取當(dāng)前變量的地址
? ??var age = 18
? ? ? age =withUnsafePointer(to: &age) { ptr in
?? ? ? ? return ptr.pointee + 21
? ? ? }
? ? ? print(age)
指針綁定API
1.assumingMemoryBound(to:) ?避免編譯器類型檢查
2.原生指針 ?bindMemory(to: capacity:)?更改內(nèi)存綁定的類型。如果當(dāng)前內(nèi)存還沒有類型綁定,則將?次綁定為該類型;否則重新綁定該類 型,并且內(nèi)存中所有的值都會(huì)變成該類型
3.類型指針 withMemoryRebound(to: capacity: body:)指針使用過程中臨時(shí)更改內(nèi)存綁定類型
指針使用實(shí)例
1.解析類的數(shù)據(jù)結(jié)構(gòu)
類的結(jié)構(gòu)體指針內(nèi)存布局
struct HeapObject {
?? var metadata: UnsafeRawPointer
?? var refCounted1: UInt32
?? var refCounted2: UInt32
}
struct Metadata{
? ? var kind: Int
? ? var superClass: Any.Type
? ? var cacheData: (Int, Int)
? ? var data: Int
? ? var classFlags: Int32
? ? var instanceAddressPoint: UInt32
? ? var instanceSize: UInt32
? ? var instanceAlignmentMask: UInt16
? ? var reserved: UInt16
? ? var classSize: UInt32
? ? var classAddressPoint: UInt32
? ? var typeDescriptor: UnsafeMutableRawPointer
? ? var iVarDestroyer: UnsafeRawPointer
}
1. 獲取實(shí)例的內(nèi)存地址(原生指針)?Unmanaged.passUnretained(t?as?AnyObject).toOpaque()
2.綁定具體類型(HeapObject)
let t = LGTeacher()
? ? ? let objRawPtr = Unmanaged.passUnretained(t as AnyObject).toOpaque()
? ? ? let objPtr = objRawPtr.bindMemory(to: HeapObject.self, capacity: MemoryLayout.stride(ofValue: t))
? ? ? let tMetaData = objPtr.pointee.metadata.bindMemory(to: Metadata.self, capacity: MemoryLayout<Metadata>.stride)
? ? ? print(MemoryLayout.stride(ofValue: t))
? ? ? print(objPtr.pointee)
? ? ? print(tMetaData.pointee)
? ? ? print("end")
2.UInt64 與指針轉(zhuǎn)換
1.UInt64 ->?指針?UnsafePointer<UInt32>.init(bitPattern:?Int(exactly: dataLoAddress) ???0)?
2.指針 ->?UInt64?UInt64(bitPattern:?Int64(Int(bitPattern: mhHeaderPtr)))
let mhHeaderPtr_IntRepresentation = UInt64(bitPattern: Int64(Int(bitPattern: mhHeaderPtr)))
? ? var dataLoAddress = mhHeaderPtr_IntRepresentation + offset
? ? var dataLoContent = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: dataLoAddress) ?? 0)?.pointee
內(nèi)存管理
Swift?中使??動(dòng)引?計(jì)數(shù)(ARC)機(jī)制來追蹤和管理內(nèi)存。
使用8字節(jié)存儲(chǔ)當(dāng)前的引?計(jì)數(shù)的。
weak 關(guān)鍵字,原來的 uint64_t 加上?個(gè)存儲(chǔ)弱引?數(shù)的 uint32_t
1.正常情況InlineRefCountBits ??strong RC?+?unowned RC?+?flags ?64位
2.加weak ?HeapObjectSideTableEntry ?strong RC?+?unowned RC?+?weak RC?+?flags ?64+32
HeapObject {?
????isa?
????InlineRefCounts {?
????????atomic<InlineRefCountBits>?{?
????????????strong RC?+?unowned RC?+?flags?
????????OR
????????HeapObjectSideTableEntry*?
????}?
????}?
}
HeapObjectSideTableEntry {?
????SideTableRefCounts {?
????????object pointer?
????????atomic<SideTableRefCountBits>?{?
????????strong RC?+?unowned RC?+?weak RC?+?flags?
????}?
????}?
}?
let t = LGTeacher()
let t1 = t
let t2 = t
print("end")
My Mac 調(diào)試的
1. MetaData 內(nèi)存地址
2.引用計(jì)數(shù)
let?t?=?LGTeacher(),?strong RC?+?unowned RC?+?flags ,?strong RC 在33位是1,?unowned RC在1位是1,flags在0位是1
Weak VS unowned?
如果兩個(gè)對(duì)象的?命周期完全和對(duì)?沒關(guān)系(其中??什么時(shí)候賦值為nil,對(duì)對(duì)?都沒影響),請(qǐng)? weak?
如果你的代碼能確保:其中?個(gè)對(duì)象銷毀,另?個(gè)對(duì)象也要跟著銷毀,這時(shí)候,可以(謹(jǐn)慎)? unowned?
常見閉包循環(huán)引用
1. 類有個(gè)complateCallback 閉包
2.complateCallback 閉包 使用實(shí)例 t.age
解決方法:?[unowned?t]?
let t = LGTeacher()
? ? ? t.complateCallback = { [unowned t] in
?? ? ? ? t.age += 1
? ? ? }
閉包循環(huán)引用
不加unowned 或 weak ,不執(zhí)行deinit{} 方法的
加入unowned 或 weak ,執(zhí)行deinit{} 方法的
捕獲列表
? ????var age = 0
? ? ? var height = 0.0
? ? ? let closure = {[age] in
?? ? ? ? print(age)
?? ? ? ? print(height)
? ? ? }
? ? ? age =10
? ? ? height =1.88
? ? ? closure()
輸出:age =??0 ?height =?1.88
[age] 捕獲閉包之前的age值
height沒有出現(xiàn)在捕獲列表中,height值是閉包調(diào)用前height的值
Enum
內(nèi)存大小
MemoryLayout<Int>.size內(nèi)存實(shí)際大小
MemoryLayout<LGPerson>.stride內(nèi)存步長
MemoryLayout<LGPerson>.alignment 字節(jié)對(duì)齊
enum Weak: Int {
?? case MONDAY = 0
?? case TUEDAY
?? case WEDDAY
?? case THUDAY
?? case FRIDAY
?? case SATDAY
?? case SUNDAY
}
1. enum 的原始值rawValue,需要明確原始值類型
Weak.MONDAY.rawValue
Weak枚舉內(nèi)存大小 1字節(jié)
var a = Weak.MONDAY
MemoryLayout.size(ofValue: a) ?1
MemoryLayout.stride(ofValue: a) ?1
enum LGEnum {
//? case test_one(Bool)
? ? case test_two(Int)
?? case test_three
?? case test_four
}
MemoryLayout<LGEnum>.size ?9
MemoryLayout<LGEnum>.stride 16
enum 內(nèi)存大小
關(guān)聯(lián)值 所有參數(shù)內(nèi)存大小 + 1字節(jié)
?sizeof(Int) * 3 + sizeof(rawVlaue)
關(guān)鍵值indirect
enum List<Element>{
? ? case end
?? indirect case node(Element, next: List<Element>)
}
enum 前面加indirect,創(chuàng)建List枚舉類型,調(diào)用swift_allocObject方法
?indirect?case?node,是node時(shí)才調(diào)用swift_allocObject方法,end不調(diào)用的
Optional是一個(gè)枚舉
enum MyOptional<Value> {
?? case some(Value)
?? case none
}