2012-12-21 39 views
0

根據this article目標C中的For循環可以使用IMP & IMP進行優化。我現在一直在想這個想法,今天我一直在嘗試一些測試。 然而,似乎爲一個班級工作,似乎並沒有爲另一個工作。此外,我想知道加速是如何發生的? 通過迴避objC_mesgSent目標C用於使用SEL和IMP進行環路優化

問題1 這是怎麼回事:

Cell *cell; 
for (NSMutableArray *row in self.data) { 
    for (Data *d in row){ 
     cell = [[Cell alloc] initWithRect:tmp_frame]; 
     [self addSubview:cell.view]; 
     [self.cells addObject:cell]; 
比這更糟糕的

SEL addCellSel = @selector(addObject:); 
IMP addCellImp = [self.cells methodForSelector:addCellSel]; 
Cell *cell; 
for (NSMutableArray *row in self.data) { 
    for (Data *d in row){ 
     cell = [[Cell alloc] initWithRect:tmp_frame]; 
     [self addSubview:cell.view]; 
     addCellImp(self.cells,addCellSel,cell); 

問題2 爲什麼會失敗? (注意自我是從UIView的繼承的類)

SEL addViewSel = @selector(addSubview:); 
IMP addViewImp = [self methodForSelector:addViewSel]; 
Cell *cell; 
for (NSMutableArray *row in self.data) { 
    for (Data *d in row){ 
     cell = [[Cell alloc] initWithRect:tmp_frame]; 
     addViewImp(self,addViewSel,cell.view); 
     [self.cells addObject:cell]; 

錯誤:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SimpleGridView addSubview:]: unrecognized selector sent to instance 0xaa3c400'

告訴我方法addSubview還沒有在我的課「SimpleGridView」被發現。 但是,當我嘗試:

if ([self respondsToSelector:addViewSel]){ 
    NSLog(@"self respondsToSelector(AddViewSel)"); 
    addViewImp(self,addViewSel,cell.view); 
} else { 
    NSLog(@"self does not respond to selector (addViewSel"); 
    [self addSubview:cell.view]; 
} 

我仍然得到完全相同的錯誤!

問題3 爲何無法設置一個選擇器&實施一類初始化/新方法,像這樣:

iContactsGridCell *cell; 
SEL initCellSel = @selector(initWithRect:); 
IMP initCellImp = [iContactsGridCell methodForSelector:initCellSel]; 
for (NSMutableArray *row in self.data) { 
    for (Data *d in row){ 
     cell = initCellImp([iContactsGridCell new],initCellSel,tmp_frame); 

參考: 類iContactsGridCell從類細胞繼承,其定義和實施

- (id) initWithRect:(CGRect)frame; 

此外,鑄造沒有幫助(約合無法識別的選擇同樣的錯誤)

iContactsGridCell *cell; 
SEL initCellSel = @selector(initWithRect:); 
IMP initCellImp = [Cell methodForSelector:initCellSel]; 
for (NSMutableArray *row in self.data) { 
    for (Data *d in row){ 
     cell = (iContactsGridCell *)initCellImp([Cell new],initCellSel,tmp_frame); 

嘗試不同的組合,如:

IMP initCellImp = [Cell methodForSelector:initCellSel]; 

或者

cell = initCellImp([iContactsGridCell class],initCellSel,tmp_frame); 

產生完全相同的錯誤。 所以,請告訴我,我錯過了什麼,這有什麼好處,是否有可能爲類初始化方法提供IMP/SEL? 此外,與此相比,C函數指針會更快嗎,還是上面所有的只是一個Objective-C函數指針包裝器? 謝謝! PS:我很抱歉,如果這些問題一次是太多的問題。

+1

爲什麼不切換到純C呢? –

+4

@RamyAlZuhouri大會。或者手動編譯原始機器碼。 (嚴重:這是一個微型優化。) – 2012-12-21 18:35:32

+0

爲了記錄,您應該在調用IMP之前將IMP投射到正確的函數原型。 –

回答

2
  1. 是的,它避免了objc_msgSend(),其中(更重要的)在基於接收器的類,並選擇運行時間爲正確的IMP來進行查找,即使在這種情況下,接收器的類,並選擇是每次都一樣,所以理論上我們可以只查看一次並重新使用它。

  2. 很難從你所描述的內容中知道什麼是錯的。一種可能性是對象的類動態地處理方法,使得它沒有針對給定選擇器的特定實現,但是當被調用時,實際上可以處理它(例如使用forwardInvocation:)。這在許多地方使用,例如代理對象或將接收到的內容發送給多個目標的通知對象。而這樣的班級可能會說YESrespondsToSelector:,因爲它確實對此做出了迴應。我不確定這是否是這裏發生的事情。

  3. [iContactsGridCell methodForSelector:initCellSel]將查找一個類方法這個名字,因爲你調用methodForSelector:iContactsGridCell,一個類對象。要獲得具有該名稱的實例方法,您必須在iContactsGridCell的實例上調用methodForSelector:,或在類上使用方法instanceMethodForSelector:

+0

謝謝您的深入解答。我有一種感覺,它不僅僅是因爲沒有提供實例,而是因爲我試圖與init方法進行動態關聯。這可以解釋爲什麼它能與實例協同工作,但不能與init/alloc方法協同工作? –

4

在該代碼中,objc_msgSend()不會導致可測量的開銷。遠遠過多的其他工作正在進行,這可能極其昂貴,包括分配,視圖層次操作和其他操作。

I.e.轉向直接函數調用是完全浪費你的時間。

目前尚不清楚代碼失敗的原因。您需要檢查返回值methodForSelector:以確保它是有道理的。另外請注意,以這種方式調用IMP是不正確的;它需要對它真正的特定類型的函數指針進行類型轉換。即void (*impPtr)(id, SEL, CGRect) ...或其他。

最後,要做到這一點速度很快,可能會涉及到使用這麼多的視圖,並轉向更多點播。這似乎是由於體系結構而導致的性能問題。