Objective C使用SEL和IMP进行循环优化

时间:2012-12-21 18:31:56

标签: objective-c optimization for-loop selector imp

根据this article目标C中的循环可以使用SEL& amp;来优化。 IMP。我现在一直在想这个想法,今天我一直在尝试一些测试。 然而,似乎对一个班级起作用的东西似乎并不适用于另一个班级。此外,我想知道加速是如何发生的? 避免使用objC_mesgSent

问题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 为什么这会失败? (注意self是一个继承自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];

错误:

  

由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [SimpleGridView addSubview:]:无法识别的选择器发送到实例0xaa3c400'

告诉我在我的类“SimpleGridView”中找不到方法addSubview。 但是,当我尝试时:

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 继承自Class Cell ,它定义并实现

- (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:如果这些问题太多,我道歉。

2 个答案:

答案 0 :(得分:4)

在该代码中,objc_msgSend()无法产生可测量的开销。还有很多其他工作正在进行中,这些工作可能非常昂贵,包括分配,视图层次结构操作和其他操作。

即。转向直接打电话是完全浪费你的时间。

目前尚不清楚代码失败的原因。您需要检查methodForSelector:的返回值,以确保它有意义。另请注意,以这种方式调用IMP是不正确的;它需要对它真正的特定类型的函数指针进行类型转换。即void (*impPtr)(id, SEL, CGRect) ...或其他什么。

最后,让这个更快可能会涉及从使用如此多的视图转变为更需要的东西。由于体系结构,这似乎是一个性能问题。

答案 1 :(得分:2)

  1. 是的,它避免了objc_msgSend(),其中(更重要的是)必须在运行时根据接收者的类和选择器为正确的IMP执行查找,即使在这种情况下,接收者的类和选择器每次都是相同的,所以理论上我们可以查看一次并重新使用它。

  2. 很难从你所描述的内容中知道出了什么问题。一种可能性是对象的类动态处理方法,使得它没有给定选择器的特定实现,但是在被调用时,实际上可以处理它(例如使用forwardInvocation:)。这用于许多地方,例如代理对象,或将收到的内容发送到多个目标的通知对象。这样的课程可能会说YESrespondsToSelector:,因为它确实会对此作出回应。我不确定这是不是这里发生了什么。

  3. [iContactsGridCell methodForSelector:initCellSel]将使用该名称查找类方法,因为您在methodForSelector:上调用了iContactsGridCell,一个类对象。要获取具有该名称的实例方法,您必须在methodForSelector:的实例上调用iContactsGridCell,或者在类上使用方法instanceMethodForSelector: