欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift中的指針操作和使用詳細(xì)介紹

 更新時(shí)間:2015年01月22日 09:01:15   投稿:junjie  
這篇文章主要介紹了Swift中的指針操作和使用詳細(xì)介紹,Apple期望在Swift中指針能夠盡量減少登場幾率,因此在Swift中指針被映射為了一個(gè)泛型類型,并且還比較抽象,本文詳細(xì)講解了Swift中指針的相關(guān)知識,需要的朋友可以參考下

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

初步

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

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

復(fù)制代碼 代碼如下:

func incrementor(ptr: UnsafeMutablePointer<Int>) { 
    ptr.memory += 1 

var a = 10 
incrementor(&a) 
a  // 11 

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

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

復(fù)制代碼 代碼如下:

func incrementor1(inout num: Int) { 
    num += 1 

var b = 10 
incrementor1(&b) 
b  // 11 

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

復(fù)制代碼 代碼如下:

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

指針初始化和內(nèi)存管理

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

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

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

復(fù)制代碼 代碼如下:

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

接下來應(yīng)該做的是對這個(gè)指針的內(nèi)容進(jìn)行初始化,我們可以使用initialize:方法來完成初始化:
復(fù)制代碼 代碼如下:

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

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

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

復(fù)制代碼 代碼如下:

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

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

指向數(shù)組的指針

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

復(fù)制代碼 代碼如下:

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ù)組則對應(yīng)UnsafeMutablePointer。使用時(shí),對于const的參數(shù),我們直接將Swift數(shù)組傳入(上例中的a和b);而對于可變的數(shù)組,在前面加上&后傳入即可(上例中的result)。

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

Buffer Pointer是一段連續(xù)的內(nèi)存的指針,通常用來表達(dá)像是數(shù)組或者字典這樣的集合類型。

復(fù)制代碼 代碼如下:

var array = [1, 2, 3, 4, 5] 
var arrayPtr = UnsafeMutableBufferPointer<Int>(start: &array, count: array.count) 
// baseAddress 是第一個(gè)元素的指針 
var basePtr = arrayPtr.baseAddress as UnsafeMutablePointer<Int> 
basePtr.memory // 1 
basePtr.memory = 10 
basePtr.memory // 10 
//下一個(gè)元素 
var nextPtr = basePtr.successor() 
nextPtr.memory // 2 

指針操作和轉(zhuǎn)換

withUnsafePointer

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

復(fù)制代碼 代碼如下:

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

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

unsafeBitCast

unsafeBitCast是非常危險(xiǎn)的操作,它會將一個(gè)指針指向的內(nèi)存強(qiáng)制按位轉(zhuǎn)換為目標(biāo)的類型。因?yàn)檫@種轉(zhuǎn)換是在Swift的類型管理之外進(jìn)行的,因此編譯器無法確保得到的類型是否確實(shí)正確,你必須明確地知道你在做什么。比如:

復(fù)制代碼 代碼如下:

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

因?yàn)镹SArray是可以存放任意NSObject對象的,當(dāng)我們在使用CFArrayGetValueAtIndex從中取值的時(shí)候,得到的結(jié)果將是一個(gè)UnsafePointer<Void>。由于我們很明白其中存放的是String對象,因此可以直接將其強(qiáng)制轉(zhuǎn)換為CFString。

關(guān)于unsafeBitCast一種更常見的使用場景是不同類型的指針之間進(jìn)行轉(zhuǎn)換。因?yàn)橹羔槺旧硭加玫牡拇笮∈且欢ǖ模灾羔樀念愋瓦M(jìn)行轉(zhuǎn)換是不會出什么致命問題的。這在與一些C API協(xié)作時(shí)會很常見。比如有很多C API要求的輸入是void *,對應(yīng)到Swift中為UnsafePointer<Void>。我們可以通過下面這樣的方式將任意指針轉(zhuǎn)換為UnsafePointer。

復(fù)制代碼 代碼如下:

var count = 100 
var voidPtr = withUnsafePointer(&count, { (a: UnsafePointer<Int>) -> UnsafePointer<Void> in 
    return unsafeBitCast(a, UnsafePointer<Void>.self) 
}) 
// voidPtr 是 UnsafePointer<Void>。相當(dāng)于 C 中的 void * 
// 轉(zhuǎn)換回 UnsafePointer<Int> 
var intPtr = unsafeBitCast(voidPtr, UnsafePointer<Int>.self) 
intPtr.memory //100 

總結(jié)

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

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

相關(guān)文章

  • 深入講解Swift中的模式匹配

    深入講解Swift中的模式匹配

    在Swift中,一些模式已經(jīng)被語言特性所吸收,你在使用Swift甚至察覺不出這類問題的存在,下面這篇文章主要給大家介紹了關(guān)于Swift中模式匹配的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-08-08
  • Swift實(shí)現(xiàn)簡單計(jì)算器項(xiàng)目

    Swift實(shí)現(xiàn)簡單計(jì)算器項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)簡單計(jì)算器項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Swift中字典與JSON轉(zhuǎn)換的方法

    Swift中字典與JSON轉(zhuǎn)換的方法

    Swift中經(jīng)常會遇到字典和字符串的相互轉(zhuǎn)換,本篇文章主要介紹了Swift中字典與JSON轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Swift?并發(fā)修改Sendable?閉包實(shí)例詳解

    Swift?并發(fā)修改Sendable?閉包實(shí)例詳解

    這篇文章主要為大家介紹了Swift?并發(fā)修改Sendable?閉包實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • SwiftUI開發(fā)總結(jié)combine原理簡單示例詳解

    SwiftUI開發(fā)總結(jié)combine原理簡單示例詳解

    這篇文章主要為大家介紹了SwiftUI開發(fā)總結(jié)combine原理簡單示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Swift教程之集合類型詳解

    Swift教程之集合類型詳解

    這篇文章主要介紹了Swift教程之集合類型詳解,Swift 提供兩種集合類型來存儲集合,數(shù)組和字典,本文詳細(xì)講解了數(shù)組的創(chuàng)建、讀取和修改數(shù)組、遍歷數(shù)組以及集合的操作等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • Swift教程之字符串和字符詳解

    Swift教程之字符串和字符詳解

    這篇文章主要介紹了Swift教程之字符串和字符詳解,本文講解了字符串常量、初始化一個(gè)空串、變長字符串、字符串不是指針,而是實(shí)際的值、字符等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • Swift泛型Generics淺析講解

    Swift泛型Generics淺析講解

    泛型代碼讓你能根據(jù)你所定義的要求,寫出可以用于任何類型的靈活的、可復(fù)用的函數(shù)。泛型是 Swift 最強(qiáng)大的特性之一,很多 Swift 標(biāo)準(zhǔn)庫是基于泛型代碼構(gòu)建的
    2022-08-08
  • Swift Json實(shí)例詳細(xì)解析

    Swift Json實(shí)例詳細(xì)解析

    這篇文章主要給大家介紹了關(guān)于Swift Json解析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • Swift 3.0基礎(chǔ)學(xué)習(xí)之閉包

    Swift 3.0基礎(chǔ)學(xué)習(xí)之閉包

    Swift引進(jìn)了閉包的概念,這個(gè)與object-c的block類似,使用過block的話都知道有多方便,所以開始學(xué)Swift,先要把閉包學(xué)會,后面使用會很頻繁。下面這篇文章主要介紹了Swift 3.0基礎(chǔ)學(xué)習(xí)之閉包的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-03-03

最新評論