根据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:如果这些问题太多,我道歉。
答案 0 :(得分:4)
在该代码中,objc_msgSend()
无法产生可测量的开销。还有很多其他工作正在进行中,这些工作可能非常昂贵,包括分配,视图层次结构操作和其他操作。
即。转向直接打电话是完全浪费你的时间。
目前尚不清楚代码失败的原因。您需要检查methodForSelector:
的返回值,以确保它有意义。另请注意,以这种方式调用IMP是不正确的;它需要对它真正的特定类型的函数指针进行类型转换。即void (*impPtr)(id, SEL, CGRect) ...
或其他什么。
最后,让这个更快可能会涉及从使用如此多的视图转变为更需要的东西。由于体系结构,这似乎是一个性能问题。
答案 1 :(得分:2)
是的,它避免了objc_msgSend()
,其中(更重要的是)必须在运行时根据接收者的类和选择器为正确的IMP执行查找,即使在这种情况下,接收者的类和选择器每次都是相同的,所以理论上我们可以查看一次并重新使用它。
很难从你所描述的内容中知道出了什么问题。一种可能性是对象的类动态处理方法,使得它没有给定选择器的特定实现,但是在被调用时,实际上可以处理它(例如使用forwardInvocation:
)。这用于许多地方,例如代理对象,或将收到的内容发送到多个目标的通知对象。这样的课程可能会说YES
到respondsToSelector:
,因为它确实会对此作出回应。我不确定这是不是这里发生了什么。
[iContactsGridCell methodForSelector:initCellSel]
将使用该名称查找类方法,因为您在methodForSelector:
上调用了iContactsGridCell
,一个类对象。要获取具有该名称的实例方法,您必须在methodForSelector:
的实例上调用iContactsGridCell
,或者在类上使用方法instanceMethodForSelector:
。