亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Swift > 正文

Swift中的指針操作和使用詳細介紹

2020-03-09 17:50:53
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了Swift中的指針操作和使用詳細介紹,Apple期望在Swift中指針能夠盡量減少登場幾率,因此在Swift中指針被映射為了一個泛型類型,并且還比較抽象,本文詳細講解了Swift中指針的相關知識,需要的朋友可以參考下
 

Apple期望在Swift中指針能夠盡量減少登場幾率,因此在Swift中指針被映射為了一個泛型類型,并且還比較抽象。這在一定程度上造成了在Swift中指針使用的困難,特別是對那些并不熟悉指針,也沒有多少指針操作經驗的開發者(包括我自己也是)來說,在Swift中使用指針確實是一個挑戰。在這篇文章里,我希望能從最基本的使用開始,總結一下在Swift中使用指針的一些常見方式和場景。這篇文章假定你至少知道指針是什么,如果對指針本身的概念不太清楚的話,可以先看看這篇五分鐘C指針教程(或者它的中文版本),應該會很有幫助。

初步

在Swift中,指針都使用一個特殊的類型來表示,那就是UnsafePointer<T>。遵循了Cocoa的一貫不可變原則,UnsafePointer<T> 也是不可變的。當然對應地,它還有一個可變變體,UnsafeMutablePointer<T>。絕大部分時間里,C中的指針都會被以這兩種類型引入到Swift中:C中const修飾的指針對應UnsafePointer(最常見的應該就是C字符串的const char *了),而其他可變的指針則對應UnsafeMutablePointer。除此之外,Swift中存在表示一組連續數據指針的UnsafeBufferPointer<T>,表示非完整結構的不透明指針COpaquePointer等等。另外你可能已經注意到了,能夠確定指向內容的指針類型都是泛型的struct,我們可以通過這個泛型來對指針指向的類型進行約束以提供一定安全性。

對于一個UnsafePointer<T>類型,我們可以通過memory屬性對其進行取值,如果這個指針是可變的UnsafeMutablePointer<T> 類型,我們還可以通過memory對它進行賦值。比如我們想要寫一個利用指針直接操作內存的計數器的話,可以這么做:

復制代碼代碼如下:

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

 

這里和C的指針使用類似,我們通過在變量名前面加上&符號就可以將指向這個變量的指針傳遞到接受指針作為參數的方法中去。在上面的incrementor中我們通過直接操作memory屬性改變了指針指向的內容。

與這種做法類似的是使用Swift的inout關鍵字。我們在將變量傳入inout參數的函數時,同樣也使用&符號表示地址。不過區別是在函數體內部我們不需要處理指針類型,而是可以對參數直接進行操作。

 

復制代碼代碼如下:

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

 

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

 

復制代碼代碼如下:

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

 

指針初始化和內存管理

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

1.內存沒有被分配,這意味著這是一個 null 指針,或者是之前已經釋放過;
2.內存進行了分配,但是值還沒有被初始化;
3.內存進行了分配,并且值已經被初始化。

其中只有第三種狀態下的指針是可以保證正常使用的。UnsafeMutablePointer的初始化方法(init)完成的都是從其他類型轉換到UnsafeMutablePointer的工作。我們如果想要新建一個指針,需要做的是使用alloc:這個類方法。該方法接受一個num: Int作為參數,將向系統申請num個數的對應泛型類型的內存。下面的代碼申請了一個Int大小的內存,并返回指向這塊內存的指針:

復制代碼代碼如下:

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

接下來應該做的是對這個指針的內容進行初始化,我們可以使用initialize:方法來完成初始化:
復制代碼代碼如下:

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

在完成初始化后,我們就可以通過memory來操作指針指向的內存值了。

 

在使用之后,我們最好盡快釋放指針指向的內容和指針本身。與initialize:配對使用的destroy用來銷毀指針指向的對象,而與alloc:對應的dealloc:用來釋放之前申請的內存。它們都應該被配對使用:

復制代碼代碼如下:

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

 

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

指向數組的指針

在Swift中將一個數組作為參數傳遞到C API時,Swift已經幫助我們完成了轉換,這在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數組的C API,其要求的類型為UnsafePointer,而非const的數組則對應UnsafeMutablePointer。使用時,對于const的參數,我們直接將Swift數組傳入(上例中的a和b);而對于可變的數組,在前面加上&后傳入即可(上例中的result)。

對于傳參,Swift進行了簡化,使用起來非常方便。但是如果我們想要使用指針來像之前用memory的方式直接操作數組的話,就需要借助一個特殊的類型:UnsafeMutableBufferPointer。

Buffer Pointer是一段連續的內存的指針,通常用來表達像是數組或者字典這樣的集合類型。

 

復制代碼代碼如下:

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  

 

指針操作和轉換

withUnsafePointer

上面我們說過,在Swift中不能像C里那樣使用&符號直接獲取地址來進行操作。如果我們想對某個變量進行指針操作,我們可以借助withUnsafePointer這個輔助方法。這個方法接受兩個參數,第一個是 inout的任意類型,第二個是一個閉包。Swift會將第一個輸入轉換為指針,然后將這個轉換后的Unsafe的指針作為參數,去調用閉包。使用起來大概是這個樣子:

復制代碼代碼如下:

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

這里其實我們做了和文章一開始的incrementor相同的事情,區別在于不需要通過方法的調用來將值轉換為指針。這么做的好處對于那些只會執行一次的指針操作來說是顯而易見的,可以將“我們就是想對這個指針做點事兒”這個意圖表達得更加清晰明確。

 

unsafeBitCast

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

復制代碼代碼如下:

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

因為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 *  
// 轉換回 UnsafePointer<Int>  
var intPtr = unsafeBitCast(voidPtr, UnsafePointer<Int>.self)  
intPtr.memory //100  

 

總結

Swift從設計上來說就是以安全作為重要原則的,雖然可能有些啰嗦,但是還是要重申在Swift中直接使用和操作指針應該作為最后的手段,它們始終是無法確保安全的。從傳統的C代碼和與之無縫配合的Objective-C代碼遷移到Swift并不是一件小工程,我們的代碼庫肯定會時不時出現一些和C協作的地方。我們當然可以選擇使用Swift重寫部分陳舊代碼,但是對于像是安全或者性能至關重要的部分,我們可能除了繼續使用C API以外別無選擇。如果我們想要繼續使用那些API的話,了解一些基本的Swift指針操作和使用的知識會很有幫助。

對于新的代碼,盡量避免使用Unsafe開頭的類型,意味著可以避免很多不必要的麻煩。Swift給開發者帶來的最大好處是可以讓我們用更加先進的編程思想,進行更快和更專注的開發。只有在尊重這種思想的前提下,我們才能更好地享受這門新語言帶來的種種優勢。顯然,這種思想是不包括到處使用 UnsafePointer的。



注:相關教程知識閱讀請移步到swift教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲小视频在线观看| 97在线观看视频| 欧美怡春院一区二区三区| 国产欧美在线观看| 日韩av网站大全| 日本成人黄色片| 色综合久久中文字幕综合网小说| 欧美电影在线观看完整版| 国产精品va在线播放| 国产精品69av| 中文在线资源观看视频网站免费不卡| 成人在线播放av| 国产狼人综合免费视频| xxxxx91麻豆| 久久国内精品一国内精品| 97在线视频免费| 久久精品视频免费播放| 亚洲自拍小视频免费观看| 久久精品在线播放| 亚洲天堂av在线免费观看| 欧美影院在线播放| 91最新在线免费观看| 国产精品老女人视频| 色琪琪综合男人的天堂aⅴ视频| 美女视频黄免费的亚洲男人天堂| 美女久久久久久久| 欧美电影免费在线观看| 日韩成人中文字幕| 欧美日韩精品在线观看| 欧美在线欧美在线| 欧美精品一本久久男人的天堂| 日本欧美爱爱爱| 国产精品亚洲第一区| 亚洲bt欧美bt日本bt| 久久久精品久久久| 亚洲韩国欧洲国产日产av| 亚洲欧美国产精品va在线观看| 精品动漫一区二区| 久久99久国产精品黄毛片入口| 久久精品小视频| 亚洲精品免费av| 久久久精品在线| 欧美日本在线视频中文字字幕| 国产91网红主播在线观看| 欧美黑人性猛交| 国产精品成久久久久三级| 亚洲国产精彩中文乱码av在线播放| 国产欧美亚洲视频| 亚洲欧美中文在线视频| 国产精品91在线| 亚洲图中文字幕| 亚洲人成在线观看| 久久在线免费观看视频| 日韩毛片在线观看| 综合激情国产一区| 欧美一级片在线播放| 欧美精品制服第一页| 91亚洲精品久久久| 一区二区三区国产视频| 伊人亚洲福利一区二区三区| 亚洲男人天堂手机在线| 亚洲精品永久免费精品| 欧美日韩国产中文字幕| 欧美激情亚洲综合一区| 日本伊人精品一区二区三区介绍| 国产情人节一区| 少妇高潮久久77777| 亚洲黄色有码视频| 亚洲性猛交xxxxwww| 色综合久久中文字幕综合网小说| 精品亚洲一区二区| 97久久超碰福利国产精品…| 久久免费精品日本久久中文字幕| 中文字幕日本精品| 日韩在线观看免费网站| 国产日韩在线免费| 国产精品爱久久久久久久| 国产成人精品在线| 超碰97人人做人人爱少妇| 国产精品视频免费在线| 久久福利视频导航| 久久91精品国产| 中文字幕亚洲欧美日韩高清| 性色av一区二区咪爱| 久久夜色精品国产亚洲aⅴ| 欧美丰满少妇xxxxx做受| 国产精品永久免费观看| 国产91色在线| 成人在线激情视频| 92国产精品久久久久首页| 日韩精品在线第一页| 国模叶桐国产精品一区| 日本一区二区三区四区视频| 91久久久久久久| 国内精品久久影院| 欧美人交a欧美精品| 亚洲电影免费观看高清完整版在线| 国产精品ⅴa在线观看h| 亚洲最新视频在线| 91九色单男在线观看| 国产丝袜一区视频在线观看| 久久精品国产v日韩v亚洲| 日本在线精品视频| 在线中文字幕日韩| 国产精品视频免费在线| 国产精品人成电影在线观看| 久久精品中文字幕电影| 色婷婷综合久久久久中文字幕1| 成人激情在线观看| 亚洲人成伊人成综合网久久久| 久久香蕉国产线看观看网| 91免费电影网站| 日韩av一区二区在线| 久久久久久亚洲| 亚洲成人激情视频| 国产精品高潮呻吟视频| 亚洲人成在线观看网站高清| 日韩电影网在线| 日韩视频免费在线观看| 国产日韩av高清| 欧美老妇交乱视频| 免费91麻豆精品国产自产在线观看| 91精品在线播放| 成人a免费视频| 国产日韩在线视频| 国产视频一区在线| 欧美激情性做爰免费视频| 福利一区视频在线观看| 欧美一区二区三区精品电影| 97视频网站入口| 国产精品免费看久久久香蕉| 国产精品白嫩美女在线观看| 亚洲电影免费观看| 欧美久久精品一级黑人c片| 亚洲欧洲激情在线| 日韩中文字幕视频在线观看| 精品电影在线观看| 国产一区二区香蕉| 成人av.网址在线网站| 日韩欧美在线视频免费观看| 国产精品久久久久久久久久免费| 国产一区二区丝袜高跟鞋图片| 国模私拍视频一区| 亚洲一级黄色av| 亚洲精品成人网| 国产精品黄页免费高清在线观看| 国产中文字幕91| 日韩三级成人av网| 热99精品只有里视频精品| 亚洲va欧美va在线观看| 成人av.网址在线网站| 亚洲综合av影视| 国产成+人+综合+亚洲欧美丁香花| 亚洲国产欧美精品| 上原亚衣av一区二区三区| 色香阁99久久精品久久久| 91视频免费网站| 欧美日韩另类在线| 一本一本久久a久久精品综合小说| 亚洲欧美日韩网| 国产欧美日韩中文字幕在线| 中文字幕国产精品| 亚洲白虎美女被爆操| 午夜免费在线观看精品视频|