標籤:des style blog color 使用 os io 資料
Swift與C指標互動
Objective-C和C API經常需要使用指標. 在設計上, Swift資料類型可以自然的與基於指標的Cocoa API一起工作, Swift自動處理幾種常用的指標參數. 在本文中, 我們將看到C中的指標參數如何與Swift中的變數,數組,字串一起工作.
指標作為輸入/輸出參數
C和Objective-C不支援多個傳回值, 所以Cocoa API經常使用指標傳遞附加參數到函數. Swift允許把指標參數看成[inout]參數, 所以你可以用同樣的&文法傳遞一個變數的引用作為指標. 例如: UIColor的getRed(_:green:blue:alpha:)方法使用4個CGFloat*指標來接受顏色的組合. 我們可以用&來得到這些值:
var r: CGFloat = 0, g:Float = 0, b:Float = 0, a:Float = 0color.getRed(&r, green: &g, blue: &b, alpha: &a)
另一個經常使用的是NSError. 許多方法使用了NSError*參數來儲存發生的錯誤. 例如: 我們列舉目錄裡的內容使用NSFileManager的contentsOfDirectoryAtPath(_:error:)方法, 直接使用NSError?變數來儲存可能的錯誤:
var maybeError:NSError? if let contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/usr/bin", error: &maybeError){ //內容處理 for i in contents{ println(i) } }else if let error = maybeError{ //錯誤處理 println(error.description) }
安全起見, Swift要求變數在使用&前需要初始化. 因為它不知道被調用的方法是否在修改它之前會讀取指標
數組指標
在C中數組與指標緊緊相連. 為方便使用基於數組的C API, Swift允許將Array作為指標. 不可修改數組可以直接當成常量指標, 可修改數組可以使用&操作符做為非常量指標(就和inout參數一樣). 例如: 我們把兩個數組 a 和 b 使用vDSP_vadd函數(Accelerte framework)相加, 把結果寫到第三個數組 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使用 const char*指標作為傳遞字串的主要方式. Swift String可以作為const char*指標, 它會給函數傳遞一個 null結束, UTF-8編碼的字串指標. 例如, 我們可以直接給標準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指標的互動方便並提供了一定的安全性, 因為C指標無處不在. 但是, 與C指標互動相對於Swift代碼來說還是記憶體的不安全, 因此需要特別注意. 特別的:
* These conversions cannot safely be used if the callee saves the pointer value for use after it returns. The pointer that results from these conversions is only guaranteed to be valid for the duration of a call. Even if you pass the same variable, array, or string as multiple pointer arguments, you could receive a different pointer each time. An exception to this is global or static stored variables. You can safely use the address of a global variable as a persistent unique pointer value, e.g.: as a KVO context parameter.
* Array和String指標沒有邊界檢查. C API不會擴大數組和字串, 因此在調用前你需要為它分配足夠的大小
如果上面的指南不滿足你指標互動的需要, 或者你想手動控制指標參數, 你可以直接使用unsafe指標操作記憶體. 我們會在將來的文章中看到更多進階應用程式.