本頁包含內(nèi)容:
Objective-C 和 C 的 API 常常會需要用到指針。Swift 中的數(shù)據(jù)類型都原生支持基于指針的 Cocoa API,不僅如此,Swift 會自動處理部分最常用的將指針作為參數(shù)傳遞的情況。這篇文章中,我們將著眼于在 Swift 中讓 C 語言指針與變量、數(shù)組和字符串共同工作。
C 和 Objective-C 并不支持多返回值,所以 Cocoa API 中常常將指針作為一種在方法間傳遞額外數(shù)據(jù)的方式。Swift 允許指針被當(dāng)作 inout 參數(shù)使用,所以你可以用符號 & 將對一個變量的引用作為指針參數(shù)傳遞。舉例來說:UIColor 中的 getRed(_:green:blue:alpha:) 方法需要四個 CGFloat* 指針來接收顏色的組成信息,我們使用 & 來將這些組成信息捕獲為本地變量:
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
另一種常見的情況是 Cocoa 中 NSError 的習(xí)慣用法。許多方法會使用一個 NSError** 參數(shù)來儲存可能的錯誤的信息。舉例來說:我們用 NSFileManager 的 contentOfDirectoryAtPath(_:error:) 方法來將目錄下的內(nèi)容列表,并將潛在的錯誤指向一個 NSError? 變量:
var maybeError: NSError?
if let contents = NSFileManager.defaultManager()
.contentsOfDirectoryAtPath("/usr/bin", error: &maybeError) {
// Work with the directory contents
} else if let error = maybeError {
// Handle the error
}
為了安全性,Swift 要求被使用 & 傳遞的變量已經(jīng)初始化。因?yàn)闊o法確定這個方法會不會在寫入數(shù)據(jù)前嘗試從指針中讀取數(shù)據(jù)。
在 C 語言中,數(shù)組和指針的聯(lián)系十分緊密,而 Swift 允許數(shù)組能夠作為指針使用,從而與基于數(shù)組的 C 語言 API 協(xié)同工作更加簡單。一個固定的數(shù)組可以使用一個常量指針直接傳遞,一個變化的數(shù)組可以用 & 運(yùn)算符將一個非常量指針傳遞。就和輸入/輸出參數(shù)指針一樣。舉例來說:我們可以用 Accelerate 框架中的 vDSP_vadd 方法讓兩個數(shù)組 a 和 b 相加,并將結(jié)果寫入第三個數(shù)組 result。
import Accelerate
let a: [Float] = [1, 2, 3, 4]
let b: [Float] = [0.5, 0.25, 0.125, 0.0625]
var result: [Float] = [0, 0, 0, 0]
vDSP_vadd(a, 1, b, 1, &result, 1, 4)
// result now contains [1.5, 2.25, 3.125, 4.0625]
C 語言中用 cont char* 指針來作為傳遞字符串的基本方式。Swift 中的 String 可以被當(dāng)作一個無限長度 UTF-8編碼的 const char* 指針來傳遞給方法。舉例來說:我們可以直接傳遞一個字符串給一個標(biāo)準(zhǔn) C 和 POSIX 庫方法
puts("Hello from libc")
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666)
if fd < 0 {
perror("could not open /tmp/scratch.txt")
} else {
let text = "Hello World"
write(fd, text, strlen(text))
close(fd)
}
Swift 很努力地使與 C 語言指針的交互更加便利,因?yàn)樗鼈儚V泛地存在于 Cocoa 之中,同時保持一定的安全性。然而,相比你的其他 Swift 代碼與 C 語言的指針交互具有潛在的不安全性,所以務(wù)必要小心使用。其中特別要注意:
如果被調(diào)用者為了在其返回值之后再次使用而保存了 C 指針的數(shù)據(jù),那么這些轉(zhuǎn)換使用起來并不安全。轉(zhuǎn)換后的指針僅在調(diào)用期間保證有效。甚至你將同樣的變量、數(shù)組或字符串作為多指針參數(shù)再次傳遞,你每次都會收到一個不同的指針。這個異常將全局或靜態(tài)地儲存為變量。你可以安全地將這段地址當(dāng)作永久唯一的指針使用。例如:作為一個 KVO 上下文參數(shù)使用的時候。
Array 或 String 時,溢出檢查不是強(qiáng)制進(jìn)行的。 基于 C 語言的 API 無法增加數(shù)組和字符串大小,所以在你將其傳遞到基于 C 語言的 API 之前,你必須確保數(shù)組或字符的大小正確。如果你需要使用基于指針的 API 時沒有遵守以上指導(dǎo),或是你重寫了接受指針參數(shù)的 Cocoa 方法,于是你可以在 Swift 中直接用不安全的指針來使用未經(jīng)處理的內(nèi)存。在未來的文章中我們將著眼于更加高級的情況。