日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

# Consumed parameters

發布時間:2025/3/21 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 # Consumed parameters 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

consumed這個單詞我并不能給出很準確的翻譯,在這篇文章中,我把Consumed parameters稱為耗用參數,它在OC中有著獨特的應用場景。

在https://clang.llvm.org/docs/AutomaticReferenceCounting.html#id7這份文檔中,講解了ARC方面的知識,我對Consumed parameters這一個小模塊有很大的疑問,因此在網上查了一些資料,雖然有了一個大概的了解,但是還是有一些不太清楚的地方。

我們先來看一個例子,這個例子來源于上邊的那份文檔:

void foo(__attribute((ns_consumed)) id x); - (void) foo: (id) __attribute((ns_consumed)) x;

我們可以用__attribute((ns_consumed))來修飾某個函數或者方法的參數,但這只是表面上的看法,實際上,它并不是只作用于它修飾的某個參數,而是作用于整個函數或方法。

它的一個限制是,只能修飾可retain的對象指針類型,比如id, Class等等,不能修飾int *這樣的類型。

上邊的兩行代碼表示foo被標記為consumed。意味著該函數的被調用者希望得到一個+1 retain count的對象。聲明了這個屬性后,當傳入一個參數時,在函數調用前,ARC會把對該參數做一次retain操作,在該函數結束后再對該參數做一次release操作,這一過程很像函數對局部變量的操作。

到這里就產生了第一個疑問?

為什么要對傳入的參數做retain,在結束時又release掉?

這個跟參數的生命周期有關,我們在函數中使用了參數,當然希望能夠得到這個參數的所有權,并且希望該參數一直存活著。這個內容我會在下邊的內容中給出一定的解釋。在上邊的文檔中有這樣一段話:

Rationale This formalizes direct transfers of ownership from a caller to a callee. The most common scenario here is passing the self parameter to init, but it is useful to generalize. Typically, local optimization will remove any extra retains and releases: on the caller side the retain will be merged with a +1 source, and on the callee side the release will be rolled into the initialization of the parameter.

這段話指出,上邊的操作直接從調用者到被調用者轉移了所有權,最常見的一個場景就是傳遞self參數到init方法之中,這個內容將是本文最重要的內容。一般來說,局部的優化會移除任何額外的retain和release操作,這句話的意思是說,在函數中,某些局部變量不一定都會十分嚴格的按照retain/release原則來進行操作。調用端將會進行一些必要的合并操作,而被調用端也會對參數做一些額外的操作。

到這里,有了第二個疑問?

在ARC中,為什么self在init方法中是一個consumed parameter?

這個問題我之前是不知道的,它來源于這個提問。init方法被標記為ns_consumes_self。ns_consumes_self說明在方法中遵循上邊講的原則,在方法調用之前先把self做retain操作,結束時做release操作。

User *user = [[User alloc] init];

這是一行非常簡單的代碼,在調用了alloc后就創建了一個User對象,這個可以在這篇回答中獲得證據。返回的對象的retain count等于1,大家應該記得,凡是通過alloc/new/copy.etc生成的對象,retain count都會+1,那么在這里的init方法中:

self = [super init]; if (self) { ... } return self;

self首先被init的調用者做了一次retain操作,此時它的retain count為1,執行完self = [super init];后,它的retain count為2,直到init返回后,self做了一次release操作,此時它的retain count為1。**這就完美保證了self在方法中是一直存活的,也保證了能夠返回一個retain count為1的對象。

有興趣可以翻看這個提問中的回答的部分,那哥們說的很詳細,再說一點,在以前的MRC時代,代碼可以這樣寫:

- (NSView *)view {//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.return [[_view retain]autorelease]; }

為了正確返回某個對象,先retain再release。

因此在使用consumed的時候,需要注意一下幾點:

  • 保證方法的接收者不能為null,因為在方法被調用之前,參會會做retain操作,這樣就帶來了內存泄漏的問題
  • 傳遞的參數的個數不能大于方法能夠動態處理的個數,否則可能引起未知的后果
  • 謹慎處理靜態類型的問題

何為靜態類型,何為動態類型?

A *a = [A new]; B *b = a;

那么b的靜態類型就是B,這個類型是由編譯器決定的,而A則是它的動態類型,由運行時決定。

我發現ASDisplayKit的源碼極其復雜,估計要花相當多的時間來解讀了。不能放棄,加油。

總結

以上是生活随笔為你收集整理的# Consumed parameters的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。