swift中的指針

Swift 中的指針使用

本文轉(zhuǎn)載自OneV's Den的blog
Apple 期望在 Swift 中指針能夠盡量減少登場幾率,因此在 Swift 中指針被映射為了一個泛型類型抖所,并且還比較抽象减噪。這在一定程度上造成了在 Swift 中指針使用的困難桨吊,特別是對那些并不熟悉指針,也沒有多少指針操作經(jīng)驗的開發(fā)者 (包括我自己也是) 來說谁鳍,在 Swift 中使用指針確實是一個挑戰(zhàn)沼死。在這篇文章里,我希望能從最基本的使用開始呕童,總結(jié)一下在 Swift 中使用指針的一些常見方式和場景漆际。這篇文章假定你至少知道指針是什么,如果對指針本身的概念不太清楚的話夺饲,可以先看看這篇五分鐘 C 指針教程 (或者它的中文版本)奸汇,應該會很有幫助施符。

初步

在 Swift 中,指針都使用一個特殊的類型來表示擂找,那就是 UnsafePointer<T>
操刀。遵循了 Cocoa 的一貫不可變原則,UnsafePointer<T>也是不可變的婴洼。當然對應地,它還有一個可變變體UnsafeMutablePointer<T>
撼嗓。絕大部分時間里柬采,C 中的指針都會被以這兩種類型引入到 Swift 中:C 中 const 修飾的指針對應 UnsafePointer(最常見的應該就是 C 字符串的 const char 了),而其他可變的指針則對應 UnsafeMutablePointer*且警。除此之外粉捻,Swift 中存在表示一組連續(xù)數(shù)據(jù)指針的 UnsafeBufferPointer<T>,表示非完整結(jié)構的不透明指針 COpaquePointer等等斑芜。另外你可能已經(jīng)注意到了肩刃,能夠確定指向內(nèi)容的指針類型都是泛型的 struct,我們可以通過這個泛型來對指針指向的類型進行約束以提供一定安全性杏头。
對于一個 UnsafePointer<T>類型盈包,我們可以通過 memory屬性對其進行取值,如果這個指針是可變的 UnsafeMutablePointer<T>類型醇王,我們還可以通過 memory對它進行賦值呢燥。比如我們想要寫一個利用指針直接操作內(nèi)存的計數(shù)器的話,可以這么做:

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

這里和 C 的指針使用類似寓娩,我們通過在變量名前面加上 &符號就可以將指向這個變量的指針傳遞到接受指針作為參數(shù)的方法中去叛氨。在上面的 incrementor中我們通過直接操作 memory 屬性改變了指針指向的內(nèi)容。與這種做法類似的是使用 Swift 的 inout關鍵字棘伴。我們在將變量傳入 inout參數(shù)的函數(shù)時寞埠,同樣也使用 &符號表示地址。不過區(qū)別是在函數(shù)體內(nèi)部我們不需要處理指針類型焊夸,而是可以對參數(shù)直接進行操作仁连。

func incrementor1(inout num: Int) { 
num += 1
}
var b = 10
incrementor1(&b)
b // 11

雖然 &在參數(shù)傳遞時表示的意義和 C 中一樣,是某個“變量的地址”阱穗,但是在 Swift 中我們沒有辦法直接通過這個符號獲取一個 UnsafePointer的實例怖糊。需要注意這一點和 C 有所不同:

// 無法編譯
let a = 100
let b = &a

指針初始化和內(nèi)存管理在 Swift 中不能直接取到現(xiàn)有對象的地址,我們還是可以創(chuàng)建新的* UnsafeMutablePointer*對象颇象。與 Swift 中其他對象的自動內(nèi)存管理不同伍伤,對于指針的管理,是需要我們手動進行內(nèi)存的申請和釋放的遣钳。一個 UnsafeMutablePointer的內(nèi)存有三種可能狀態(tài):

-內(nèi)存沒有被分配扰魂,這意味著這是一個 null 指針,或者是之前已經(jīng)釋--放過
-內(nèi)存進行了分配,但是值還沒有被初始化
-內(nèi)存進行了分配劝评,并且值已經(jīng)被初始化

其中只有第三種狀態(tài)下的指針是可以保證正常使用的姐直。UnsafeMutablePointer的初始化方法 (init) 完成的都是從其他類型轉(zhuǎn)換到 UnsafeMutablePointer的工作。我們?nèi)绻胍陆ㄒ粋€指針蒋畜,需要做的是使用 alloc:這個類方法声畏。該方法接受一個 num: Int
作為參數(shù),將向系統(tǒng)申請 num個數(shù)的對應泛型類型的內(nèi)存姻成。下面的代碼申請了一個 Int大小的內(nèi)存插龄,并返回指向這塊內(nèi)存的指針:

var intPtr = UnsafeMutablePointer<Int>.alloc(1)
// "UnsafeMutablePointer(0x7FD3A8E00060)"

接下來應該做的是對這個指針的內(nèi)容進行初始化,我們可以使用 initialize:方法來完成初始化:

intPtr.initialize(10)
// intPtr.memory 為 10

在完成初始化后科展,我們就可以通過 memory來操作指針指向的內(nèi)存值了均牢。在使用之后,我們最好盡快釋放指針指向的內(nèi)容和指針本身才睹。與 initialize:配對使用的 destroy用來銷毀指針指向的對象徘跪,而與 alloc:
對應的 dealloc:用來釋放之前申請的內(nèi)存。它們都應該被配對使用:

intPtr.destroy()
intPtr.dealloc(1)
intPtr = nil

注意其實在這里對于 Int這樣的在 C 中映射為 int 的 “平凡值” 來說琅攘,destroy并不是必要的垮庐,因為這些值被分配在常量段上。但是對于像類的對象或者結(jié)構體實例來說坞琴,如果不保證初始化和摧毀配對的話突硝,是會出現(xiàn)內(nèi)存泄露的。所以沒有特殊考慮的話置济,不論內(nèi)存中到底是什么解恰,保證 initialize:和 destroy配對會是一個好習慣。

指向數(shù)組的指針

在 Swift 中將一個數(shù)組作為參數(shù)傳遞到 C API 時浙于,Swift 已經(jīng)幫助我們完成了轉(zhuǎn)換护盈,這在 Apple 的官方博客中有個很好的例子:

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]

對于一般的接受 const 數(shù)組的 C API,其要求的類型為 UnsafePointer羞酗,而非 const 的數(shù)組則對應 UnsafeMutablePointer
腐宋。使用時,對于 const 的參數(shù)檀轨,我們直接將 Swift 數(shù)組傳入 (上例中的 a和 b)胸竞;而對于可變的數(shù)組,在前面加上 &后傳入即可 (上例中的 result)参萄。
對于傳參卫枝,Swift 進行了簡化,使用起來非常方便讹挎。但是如果我們想要使用指針來像之前用 memory的方式直接操作數(shù)組的話校赤,就需要借助一個特殊的類型:UnsafeMutableBufferPointer吆玖。Buffer Pointer 是一段連續(xù)的內(nèi)存的指針,通常用來表達像是數(shù)組或者字典這樣的集合類型马篮。

var array = [1, 2, 3, 4, 5]
var 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

指針操作和轉(zhuǎn)換
withUnsafePointer
上面我們說過沾乘,在 Swift 中不能像 C 里那樣使用 &
符號直接獲取地址來進行操作。如果我們想對某個變量進行指針操作浑测,我們可以借助 withUnsafePointer
這個輔助方法翅阵。這個方法接受兩個參數(shù),第一個是 inout
的任意類型迁央,第二個是一個閉包掷匠。Swift 會將第一個輸入轉(zhuǎn)換為指針,然后將這個轉(zhuǎn)換后的 Unsafe
的指針作為參數(shù)漱贱,去調(diào)用閉包夭委。使用起來大概是這個樣子:
var test = 10test = withUnsafeMutablePointer(&test, { (ptr: UnsafeMutablePointer<Int>) -> Int in ptr.memory += 1 return ptr.memory})test // 11

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市株灸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慌烧,老刑警劉巖逐抑,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異厕氨,居然都是意外死亡,警方通過查閱死者的電腦和手機命斧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘱兼,“玉大人国葬,你說我怎么就攤上這事∏酆荆” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵通孽,是天一觀的道長睁壁。 經(jīng)常有香客問我挨厚,道長,這世上最難降的妖魔是什么疫剃? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任硼讽,我火速辦了婚禮,結(jié)果婚禮上固阁,老公的妹妹穿的比我還像新娘。我一直安慰自己碉克,他們只是感情好并齐,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著况褪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捏膨。 梳的紋絲不亂的頭發(fā)上食侮,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音锯七,去河邊找鬼诚隙。 笑死起胰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的效五。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼脉执,長吁一口氣:“原來是場噩夢啊……” “哼戒劫!你這毒婦竟也來了婆廊?” 一聲冷哼從身側(cè)響起巫橄,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎湘换,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筹我,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡帆离,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年哥谷,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呼巷。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡赎瑰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出压储,到底是詐尸還是另有隱情,我是刑警寧澤源譬,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站刮刑,受9級特大地震影響养渴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜理卑,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帆疟。 院中可真熱鬧,春花似錦踪宠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肖粮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涩馆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工蛾号, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涯雅,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓精刷,卻偏偏與公主長得像蔗候,于是被迫代替她去往敵國和親怒允。 傳聞我的和親對象是個殘疾皇子锈遥,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 雖然在Swift中是不推薦直接訪問指針的所灸,但是Swift還是保留了訪問指針的方法,當然庆寺,完全拋棄C一套的東西還是相...
    TomatosX閱讀 2,740評論 0 1
  • 作者:Umberto Raimondi懦尝,原文鏈接知纷,原文日期:2016-04-07譯者:shanks;校對:pmst...
    梁杰_numbbbbb閱讀 5,469評論 0 20
  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型伍绳。 運用指針編程是C語言最主要的風格之一乍桂。利用指針變量可以表示各種數(shù)據(jù)結(jié)構; ...
    朱森閱讀 3,444評論 3 44
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫权谁、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,102評論 4 62
  • “錯誤”這兩個字很有意思旺芽,“錯”中的“日”辐啄,藏在了右下角;“誤”中的“天”也是一樣壶辜。這兩個字結(jié)緣,看來不是偶然砸民。 ...
    石竹閱讀 1,042評論 19 15