鏈接器將靜態庫視爲一個大型的隨機碎片集合,它將從中抽取單個碎片以滿足來自鏈接單元其餘部分的任何符號請求。
I.e.如果主程序調用_foo
和_foo
只出現在靜態庫,然後_foo
,與任何相關的符號一起,將在拖動。
然而,當你在一個類別調用一個方法,沒有特定的符號引用由於Objective-C的活力。
-ObjC
標誌告訴鏈接器,因此,它應該從靜態庫中抓取所有類別,並將它們放入主二進制文件中。
這是一個有點混亂,假設是編譯器應該是這個聰明(和,無疑,它應該給在開發工具一級的援助)。重要的是要記住一些事情:
在鏈接器滾動時,頭文件中聲明的任何內容都會丟失。符號由編譯單元創建,而不是由頭文件創建。頭文件很大程度上產生了一個承諾,即一個符號將在後面被具體創建或由該鏈接完成,但不能自己創建符號(否則每個編譯單元 - 每個.o)最終會得到鏈接時會出現符號和歡鬧)。
Objective-C是完全動態的。當你說[(id)foo bar];
時,唯一的要求是bar
被定義爲某處之前。無論它是否實際上實現(無論如何,直到運行時)都無關緊要。
類別不必具有相應的@implementations;一個類別可以用來聲明方法可能存在,事實上,在將@optional
添加到@protocol
之前,通常使用NSObject
(ewwwwww)上的類別沒有@implementation
來說「嘿,這個可選方法可能存在於運行時」。
編譯和鏈接是完全獨立的過程。編譯完全是關於擴展代碼並將其轉換爲可執行字節的庫。鏈接是關於將這些庫合併成一些可以實際運行的庫,包括解決庫之間的所有依賴關係。編譯器並不真正瞭解鏈接的方式,鏈接器也沒有關於可能已經定義了哪些東西(不會產生硬符號)的任何信息。
最終結果?
鏈接器沒有足夠的信息來解決依賴關係。
但編譯器知道它看到了一個在類別中定義的方法的調用,所以它*可以*創建一個特定的符號引用,以便在鏈接時使用 - 這就是我的問題所在。我想了解這一點比我所鏈接的技術問答中已經描述的更深。 – jhabbott
很好的答案 - 一個問題。什麼足以導致編譯器鏈接靜態庫中的符號。只需'#import'或者只是定義一個變量'MyClass c;',或者你需要調用一個類['myMethod]'的方法嗎?如果該類僅在界面構建器中引用,那麼該怎麼辦? – Robert
@Robert鏈接器需要看到一個通過與庫的硬鏈接解決的符號。如果它是在運行時動態解析的符號,它將不會計數(如IB)。它不一定是一個方法調用,但這是最容易使用的機制。即例如'[MyClass class];'。 – bbum