目的:利用SEL和IMP进行循环优化



根据本文,objective C中的For循环可以使用SEL进行优化;我一直在考虑这个想法,今天我做了一些测试。然而,似乎对一个班级有用的东西,似乎对另一个班级不起作用。此外,我想知道加速究竟是如何发生的?通过避免objc_messgsent ?

问题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'

告诉我方法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 为什么我不能设置一个选择器&Class Init/new方法的实现如下:

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继承自类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:如果你一次问的问题太多了,我很抱歉。

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

。直接调用函数完全是浪费时间。

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

最后,要使它更快,可能需要从使用这么多视图转向更按需的东西。

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

  2. 很难从你的描述中知道哪里错了。一种可能性是对象的类动态处理方法,这样它就没有给定选择器的特定实现,但是当被调用时,可以实际处理它(例如使用forwardInvocation:)。这在很多地方都有使用,例如代理对象,或者将接收到的东西发送到多个目标的通知对象。这样的类可能会说YESrespondsToSelector:,因为它确实响应它。

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

相关内容

  • 没有找到相关文章

最新更新