2012-12-21 21 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) ...或其他。

最后,要做到这一点速度很快,可能会涉及到使用这么多的视图,并转向更多点播。这似乎是由于体系结构而导致的性能问题。