根据本文,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) ...
或其他。
最后,要使它更快,可能需要从使用这么多视图转向更按需的东西。
-
是的,它避免了
objc_msgSend()
,(更重要的是)必须在运行时根据接收器的类和选择器为正确的IMP执行查找,即使在这种情况下,接收器的类和选择器每次都是相同的,所以理论上我们可以只查找一次并重复使用它。 -
很难从你的描述中知道哪里错了。一种可能性是对象的类动态处理方法,这样它就没有给定选择器的特定实现,但是当被调用时,可以实际处理它(例如使用
forwardInvocation:
)。这在很多地方都有使用,例如代理对象,或者将接收到的东西发送到多个目标的通知对象。这样的类可能会说YES
到respondsToSelector:
,因为它确实响应它。 -
[iContactsGridCell methodForSelector:initCellSel]
将查找具有该名称的类方法,因为您在iContactsGridCell
上调用methodForSelector:
,一个类对象。要获得具有该名称的实例方法,必须在iContactsGridCell
的实例上调用methodForSelector:
,或者在类上使用instanceMethodForSelector:
方法。