簡體   English   中英

協議對象是否具有靜態存儲期限?

[英]Do protocol objects have static storage duration?

當您將@protocol(SomeProtocol)作為方法的參數傳遞時,是否可以將結果指針視為具有靜態存儲持續時間?

現在考慮該協議是在.h文件中的編譯時定義的,這是否意味着它的指針在程序的整個生命周期中都是相同的,並且可以安全地在運行時稱為靜態的?

TL; DR:是的,但有一些警告。

關於什么是Protocol指針,存在一些非常明顯的困惑,因此我將嘗試消除與此有關的任何困惑。

早在ObjC的早期,協議就根本不存在。 因此,當NeXT的API需要多重繼承時,他們將其“砍”成一種自己的語言,並用特殊的語法修改了編譯器以接受這種情況。

它的工作很好,直到ObjC2卷左右,而協議將要添加為官方語言(和運行時API)功能,但是這引起了一些向后兼容的問題,因為我們已經有了一個Protocol ,是由定義的類下一個。

隨之而來的解決方案是保留Protocol類,但不贊成使用。 因此,從技術上講,我們仍然可以在運行時中使用Protocol類,但是沒有一種方法可以在ObjC2中工作(實際上,很多舊的結構​​都是這樣,例如forward::選擇器, objc_msgSendv和一些其他小事,但我離題)。

您不應該(無法讀取)向此類發送消息-盡管從技術上講,它仍是一個對象,但您不應期望它符合應用程序中存在的其他對象的相同約定(協議?)。

因此,解決方案是在運行時中使用以protocol_為前綴的函數,例如:

  • protocol_getName()而不是-name
  • protocol_conformsToProtocol()代替-conformsTo:

等等

請注意,在協議類的當前實現下,這些方法實際上仍然可以被調用,並且只是它們的C函數對應項的填充。

話雖如此,如果您的所有協議都是通過使用objc_getProtocol獲得的,則在當前版本的運行時中,可以保證它們具有“靜態”存儲,正如我們在實現中看到的那樣:

/***********************************************************************
* objc_getProtocol
* Get a protocol by name, or return nil
* Locking: read-locks runtimeLock
**********************************************************************/
Protocol *objc_getProtocol(const char *name)
{
    rwlock_read(&runtimeLock); 
    Protocol *result = (Protocol *)NXMapGet(protocols(), name);
    rwlock_unlock_read(&runtimeLock);
    return result;
}

沒有協議的副本,並且每個后續調用都將返回相同的指針。 這也適用於使用@protocol(name)表達式,該表達式實質上可以(盡管不完全是,還有其他一些編譯器魔術可以完成)被視為對objc_getProtocol的調用。

現在-這是,然而,理論上可能是有人故意制造協議“對象”的副本,因為結構非常簡單,所概述這里

struct protocol_t : objc_object {
    const char *name;
    struct protocol_list_t *protocols;
    method_list_t *instanceMethods;
    method_list_t *classMethods;
    method_list_t *optionalInstanceMethods;
    method_list_t *optionalClassMethods;
    property_list_t *instanceProperties;
    uint32_t size;   // sizeof(protocol_t)
    uint32_t flags;
    const char **extendedMethodTypes;
};

(請注意,這是一個模仿Objective-C對象的C ++結構,如果您嘗試自己模擬它,可能會導致一些困難)。

這里要注意的重要一點是, memcpy運行時給您的協議指針執行memcpy會導致很少的問題,因此,您應始終使用protocol_isEqual()來比較協議,這將檢查協議字段以確保它們實際上等效,即使它們具有不同的指針也是如此。

但是,簡單地將Protocol *視為靜態是完全可以的,並且是在代碼中引用協議的正確方法。

請注意,但是,與任何運行時功能一樣,所有這些都可能會因API的另一個版本,編譯器,ABI,目標體系結構以及其他情況而發生變化,因此請務必閱讀有關最新信息。學科!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM