Swift 中的指針使用


SWIFT 中  指針被映射為泛型 

UnsafePointer<T> 

UnsafeMutablePointer<T>

表示一組連續數據指針的 UnsafeBufferPointer<T>

表示非完整結構的不透明指針 COpaquePointer 等等

 

UnsafePointer<T> 通過 memory 屬性對其進行取值,如果這個指針是可變的 UnsafeMutablePointer<T> 類型,我們還可以通過 memory 對它進行賦值。

func incrementor(ptr: UnsafeMutablePointer<Int>) { 
    ptr.memory += 1 
} 
 
var a = 10 
incrementor(&a) 
a  // 11 

swift中&同樣可以取地址, 但無法直接獲取一個指針實例

var a = 10
//let ptr:UnsafeMutablePointer<Int> = &a // 'inout Int' is not convertible to 'UnsafeMutablePointer<Int>'
//let ptr2 = &a                          // 報錯
func incrementor1(inout num: Int) {
    num += 1
}

var b = 10
incrementor1(&b)
b   // 11
[1,2,3] + 1  // 不報錯,Playground顯示一個地址值
([1,2,3] + 1)[-100]  // 不報錯
([1,2,3] + 1)[30]

var array = [1,2,3]
//array + 1     //報錯
 //let ptr:UnsafeMutableBufferPointer<Int> = array  //報錯

 當使用inout運算符時,使用var聲明的變量和使用let聲明的常量被分別轉換到UnsafePointer和UnsafeMutablePoinger

 

 在 Swift 中不能直接取到現有對象的地址,我們還是可以創建新的 UnsafeMutablePointer 對象。與 Swift 中其他對象的自動內存管理不同,對於指針的管理,是需要我們手動進行內存的申請和釋放的。

// 將向系統申請 1 個 Int 大小的內存,並返回指向這塊內存的指針
var intPtr = UnsafeMutablePointer<Int>.alloc(1)
// 初始化
intPtr.initialize(10)
var intPtr2 = intPtr.successor()
intPtr2.initialize(50)
// 讀取值
intPtr.memory   // 10
intPtr2.memory   // 20

//intPtr.dealloc(1)
//intPtr.destroy(1)//
intPtr.destroy()
intPtr2 = nil
//intPtr2.memory  // 奔潰



var array = [1,2,3]
let arrayPtr = UnsafeMutableBufferPointer<Int>(start: &array, count: array.count)
// baseAddress 是第一個元素的指針
var basePtr = arrayPtr.baseAddress as UnsafeMutablePointer<Int>

basePtr.memory // 1
basePtr.memory = 10
basePtr.memory // 10

//下一個元素
var nextPtr = basePtr.successor()
nextPtr.memory // 2

 直接操作變量地址 withUnsafePointer,withUnsafePointers

var test = 10
test = withUnsafeMutablePointer(&test, { (ptr: UnsafeMutablePointer<Int>) -> Int in
    ptr.memory += 1
    return ptr.memory
})

test // 11

 

unsafeBitCast

unsafeBitCast 是非常危險的操作,它會將一個指針指向的內存強制按位轉換為目標的類型。因為這種轉換是在 Swift 的類型管理之外進行的,因此編譯器無法確保得到的類型是否確實正確,你必須明確地知道你在做什么。比如:

let arr = NSArray(object: "meow")
let str = unsafeBitCast(CFArrayGetValueAtIndex(arr, 0), CFString.self)
str // “meow”

let arr2 = ["meow2"]
let str2 = unsafeBitCast(CFArrayGetValueAtIndex(arr2, 0), CFString.self)

 

因為 NSArray 是可以存放任意 NSObject 對象的,當我們在使用 CFArrayGetValueAtIndex 從中取值的時候,得到的結果將是一個 UnsafePointer<Void>。由於我們很明白其中存放的是 String 對象,因此可以直接將其強制轉換為 CFString。

關於 unsafeBitCast 一種更常見的使用場景是不同類型的指針之間進行轉換。因為指針本身所占用的的大小是一定的,所以指針的類型進行轉換是不會出什么致命問題的。這在與一些 C API 協作時會很常見。比如有很多 C API 要求的輸入是 void *,對應到 Swift 中為 UnsafePointer<Void>。我們可以通過下面這樣的方式將任意指針轉換為 UnsafePointer。

var count = 100
var voidPtr = withUnsafePointer(&count, { (a: UnsafePointer<Int>) -> UnsafePointer<Void> in
    return unsafeBitCast(a, UnsafePointer<Void>.self)
})
// voidPtr 是 UnsafePointer<Void>。相當於 C 中的 void *
voidPtr.memory //Void

// 轉換回 UnsafePointer<Int>
var intPtr = unsafeBitCast(voidPtr, UnsafePointer<Int>.self)
intPtr.memory //100

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM