淺談Unmanaged

最近學習Swift內存相關的東西,接觸到了Unmanaged這個類型,在網上看了很多文檔,個人感覺講的比較晦澀,所以寫下這篇筆記方便自己理解和總結。

Unmanaged解決的是在Swift中調用C函數(shù)時,C函數(shù)返回CoreFoundation類型的對象內存管理相關的問題,它的出現(xiàn)屬于歷史原因而作為臨時的過渡方案。

在ARC下,所有的OC對象和從OC方法返回的CoreFoundation類型的對象都能由編譯器自動管理內存。而通過C語言返回的CoreFoundation類型的對象仍然需要CFRetain、CFRelease來手動管理引用計數(shù),或者橋接到OC對象上。

蘋果通過在C函數(shù)命名中使用Create\Copy、Get字眼,讓調用者明白返回的對象是否被調用者持有。比如我們調用包含Create\Copy的C函數(shù)返回的對象,需要我們對其使用CFRelease函數(shù)進行手動釋放。

CFAttributedStringRef attrStrRef = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"Hello", NULL);
CFRelease(attrStrRef);//需要手動釋放

而調用包含Get的C函數(shù)返回的對象則不需要手動釋放,如果我們需要持有這個返回對象,則需要對其調用CFRetain函數(shù)。

Swift只支持ARC,所以沒有retain、release這些方法,在Swift和OC混編的時候,編譯器也能很好的幫我們自動管理內存,除了上面說的C函數(shù)返回CoreFundation對象。

舉個例子,我們使用蘋果的命名規(guī)范聲明一個C函數(shù):

//聲明
CFStringRef CreateJoinedString(CFStringRef s1, CFStringRef s2);

//實現(xiàn)
CFStringRef CreateJoinedString(CFStringRef s1, CFStringRef s2) {
    CFMutableStringRef resultString = CFStringCreateMutableCopy(NULL, 0, s1);
    CFStringAppend(resultString, s2);
    return resultString;
}

然后在Swift中進行調用:


圖1

可以看到橋接到Swift中的方法的返回值是一個Unmanaged<CFString>!類型,為什么會返回這個類型?因為在OC中編譯器都不能幫我們自動管理C函數(shù)返回的CoreFoundation對象,更別說Swift橋接調用C函數(shù)了。所以編譯器這時候不知道如何管理這個C函數(shù)返回對象的引用計數(shù),在翻譯成Swift代碼時將其包裝成了Unmanaged類型的對象。這個類型現(xiàn)在只關注如下兩個方法。

    //都是取值,區(qū)別在于
    //這個方法在取值時不會改變引用值的引用計數(shù)
    public func takeUnretainedValue() -> Instance
    //這個方法返回引用值并對引用值進行一次release(引用計數(shù)減1)
    public func takeRetainedValue() -> Instance

這其實就是將對象的內存管理交給調用者自己處理,相當于在Swift中變相提供了手動release操作。通過調用需要我們手動釋放內存的函數(shù)而獲得的對象時,使用takeRetainedValue進行取值,否則使用takeUnretainedValue,也就是蘋果在CoreFoundation中使用Create/Get命名方式的那些函數(shù)。

當然我們自己在寫這種C函數(shù)時要避免在Swift中被包裝成Unmanaged類型,可以使用CF_IMPLICIT_BRIDGING_ENABLEDCF_IMPLICIT_BRIDGING_DISABLED這兩個宏將函數(shù)聲明包裹起來,這是告訴clang編譯器:不需要為Swift橋接審查和處理這些函數(shù)的CoreFoundation類型(即Annotated APIs,向編譯器注明該方法可自動管理)

CF_IMPLICIT_BRIDGING_ENABLED

CFStringRef CreateJoinedString(CFStringRef s1, CFStringRef s2);

CF_IMPLICIT_BRIDGING_DISABLED

再回到Swift調用可以看到返回值不在是Unmanaged類型,而是C函數(shù)一樣直接返回CFString


圖2

現(xiàn)在大部分CoreFoundation的方法都已經面向Swift進行了優(yōu)化,返回值沒有被Unmanaged包裝,但還有部分API沒有被注明可自動管理,比如AddressBook。

查看AddressBook的方法聲明,可以看到很多方法的返回值類型是Unmanaged類型


圖3

可能由于蘋果來不及對這些API進行處理吧,所以正如文初所說,Umagnage是因為歷史原因(Swift 的API橋接OC的API,OC底層又是C的實現(xiàn))和作為過渡方案的產物。隨著Swift的完善,可能會越來越少甚至不會再見到這樣的API。自己寫的C函數(shù)要盡量避免這樣的情況。

參考:https://nshipster.cn/unmanaged/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 背景 大部分情況下做Swift開發(fā)是不需要使用指針的,也不建議使用,但是有時候寫比較底層的東西就需要了。最近一段時...
    小涼介閱讀 2,371評論 1 7
  • 參考文獻 Swift結構體指針操作官方文檔Swift 和 C 不得不說的故事Swift指針和托管,你看我就夠了 W...
    沉靜BBQ閱讀 8,211評論 1 25
  • Unmanaged使用 作者 Nate Cook 翻譯者 Croath Liu 2015年4月13日 API...
    藍色的風閱讀 2,822評論 0 2
  • 指針 Swift中指針分為兩類: typed pointer:指定數(shù)據(jù)類型指針,UnsafePointer<T>,...
    YY323閱讀 3,032評論 0 1
  • 文章已發(fā)在快手大前端公眾號,歡迎關注,文章地址如下: A站 的 Swift 實踐 —— 上篇[https://mp...
    星光社的戴銘閱讀 3,259評論 4 35

友情鏈接更多精彩內容