在Objective-c
的世界中,一切對象都是指針。它是一種運行時語言,具體指針的對象類型將會在運行時,由系統分配。這樣雖然自由,可是卻並不安全。編程
Swift
世界就不同了,Swift
的世界很安全(至少大部分時候狀況如此)。咱們沒必要爲對象運行時的類型擔心,這是Swift
爲咱們構築的一層堡壘。可是在一些時候,這層堡壘也成爲束縛咱們行爲的操做。swift
Swift
也爲操做指針這種不安全行爲提供了支持。數組
MemoryLayout
MemoryLayout
是Swift 爲結構體struct
等一些須要獲取具體內存空間大小定義的枚舉。安全
它包含一系列方法,可使咱們更方便的使用。bash
主要屬性就是三個:socket
/// 對應類型的實例在內存佔用的真實字節大小
public static var size: Int { get }
/// 對應類型的實例在內存通過對齊後佔用的字節大小 (內存對齊請參照百度百科,連接將會在下文給出)
public static var stride: Int { get }
/// 默認內存對齊單位
public static var alignment: Int { get }
複製代碼
內存對齊百度百科: baike.baidu.com/item/內存對齊/9…編程語言
這三個屬性也是咱們常用的,對應還有三個從實例對象中獲取的方法ide
playgroud 介紹代碼函數
struct Test {
let res1: Bool = false
let res2: Int = 0
let res3: Bool = false
}
print("\(MemoryLayout<Test>.stride)") // 24
複製代碼
由於這個類不是咱們首要要介紹的,因此就只是大概介紹學習
指針定義:
在計算機科學中,**指針(Pointer)**是編程語言中的一個對象,利用地址,它的值直接指向(points to)存在電腦存儲器中另外一個地方的值。因爲經過地址能找到所需的變量單元,能夠說,地址指向該變量單元。所以,將地址形象化的稱爲「指針」。意思是經過它能找到以它爲地址的內存單元。
節選自百度百科: baike.baidu.com/item/指針/287…
Swift
中認爲全部的指針相關操做都是不安全的,因此全部指針相關的結構體都會包含有前綴Unsafe
Swift
中一共有8個結構體
Swift | Objective-c | 描述 |
---|---|---|
UnsafePointer<T> |
const T * |
指針及其所指向的內存內容均不可變 |
UnsafeMutablePointer<T> |
T * |
指針及其所指向的內存內容都可變 |
UnsafeBufferPointer<T> |
const T * [] |
是一個指針數組內容均不可變 |
UnsafeMutableBufferPointer<T> |
T * [] |
|
UnsafeRawPointer |
const void * |
|
UnsafeMutableRawPointer |
void * |
|
UnsafeBufferRawPointer |
void * [] |
首先要說一個實例類對象如何轉化爲指針
UnsafePointer
代碼展現:
struct Obj {
var name: Int = 5
}
var obj = Obj()
let pointer = withUnsafePointer(to: &obj, {$0})
print("\(pointer.pointee)")
複製代碼
這裏注意了,UnsafePointer.pointee
只有get
方法,也就是至關於咱們獲取了一個let
的對象,聽從於let
的相關要求。
注:這裏多介紹一下let
和var
的區別
let
和var
都是swift
聲明變量時候的前綴。在程序中,當咱們聲明變量的時候,在真實運行時候的環境裏,程序便會爲咱們聲明的變量初始化對應的內存。
let
聲明的變量的內存內容,在聲明初始化事後便再也不可變
var
聲明的變量的內存內容,在隨後能夠隨時被修改。這裏咱們使用的是內存內容,也就是抽象的內存地址裏的那些0、1的值。
對於
class
,let
和var
的區別是這個變量能不能再被賦值一個新的類對象,而對原有對象的相關存儲屬性的修改,並不受影響。這是由於class
的對象在聲明時候的堆棧內存內容,只有8個字節(咱們可使用MemoryLayout
獲取),真實對象的存儲在其餘位置。因此咱們能修改let
指向的值對於
struct
,let
和var
的區別就是let
建立的對象,不論屬性是用let
仍是var
,咱們都沒法直接修改值。只能修改var
修飾的。這個是由於struct
對象是直接存儲在聲明時候的內存內容裏。
對於UnsafeMutablePointer來講,pointee即是set
和get
方法了,也就是說,咱們能夠直接修改對應內存地址的值了。
這裏展現下如何獲取UnsafeMutablePointer與修改相關值
struct Obj {
var name: Int = 5
init(name: Int = 5) {
self.name = name
}
}
var obj = Obj()
let pointer = withUnsafeMutablePointer(to: &obj, {$0})
print("Obj: \(obj)")
pointer.pointee = Obj(name: 10)
print("\(pointer.pointee)")
print("Obj: \(obj)")
複製代碼
當運行這段代碼的時候,咱們能夠看到,obj
的內容也隨着指針變化了。
注:obj
只能使用var
聲明,由於Unsafe
類的調用須要使用&
,同時有可能產生內存內容的變化,所以let
定義下不符合相關要求。
接下來是我要講的就是Swift中等同於C語言中void *
的指針UnsafeRawPointer
在蘋果的官方文檔中,關於UnsafeRawPointer
的定義爲
A raw pointer for accessing untyped data.
一個用來訪問未定義類型的指針
Overview
The UnsafeRawPointer type provides no automated memory management, no type safety, and no alignment guarantees. You are responsible for handling the life cycle of any memory you work with through unsafe pointers, to avoid leaks or undefined behavior.
UnsafeRawPointer 提供了沒有自動內存管理,沒有類型安全,與內存對齊控制保證。你有義務去本身管理你經過指針引用的任何內存的聲明週期,以免內存泄漏或者其他未定義(不安全)的行爲
Memory that you manually manage can be either untyped or bound to a specific type. You use the UnsafeRawPointer type to access and manage raw bytes in memory, whether or not that memory has been bound to a specific type.
你手動管理的內存能夠是未定義內存的,或者是被定義到一個指定的類型的。你可使用UnsafeRawPointer去訪問和管理未被定義的內存字節,而無需在乎這段內存是否已經被綁定到一個指定的類型。
官方定義是這樣的,大體思路就是,若是你有需求須要本身管理內存的時候,使用這個類。通常就是咱們操做底層的一些代碼,這個會須要被當成參數傳入。
代碼示例:
var i = 2
let pointerRaw = withUnsafeBytes(of: &i, {$0})
guard let pointer = pointerRaw.bindMemory(to: Int.self).baseAddress else { fatalError("這段代碼理論上不能執行到這") }
let j = pointer.pointee
print("j:\(j)")
複製代碼
以上代碼就是轉換rawPointer和pointer的例子了。剩下的是bufferPointer,由於使用的地方較少了,故此不深刻介紹了。
指針相關中最重要的幾個操做就是指針的生成,與將指針轉化成實例對象。其中重要的就是pointee
和幾個withUnsafeXX
的全局函數。
在swift
中,指針的世界並不複雜,全部指針的操做都能轉化爲8個UnsafeXX
類。咱們的使用也是基於此的,咱們若是使用某些底層方法須要指針,這個時候只須要將相應的指針對象生成便可傳入。
一轉眼已經元旦了,期間也想過寫一些文章,可是對於沒什麼東西要寫感到困惑。同時,這段時間也是一直在學習Swift
的相關語言。由於我的項目中將要用到socket操做,因而決定用Swift
重寫GCDAsyncSocket
。在重寫過程當中遇到了不少指針相似的問題,因而決定寫一篇關於指針的教程。
Swift的socket庫SwiftAsyncSocket
目前正在完善中,TCP/IP協議基礎功能已基本完善。近期將會正式開源
本文首發於,本人博客與公衆號(見下圖),若是但願轉載到公衆號,請聯繫本人開通權限。
最後,祝你們新年快樂,心想事成