Cocoa 如何重构调用super的代码中的重复性
我有两个NSResponder方法(cut、copy),它们的代码基本相同,只是它们调用自己的super。如何创建以参数_CMD作为选择器的方法来调用super,而不会以递归结束Cocoa 如何重构调用super的代码中的重复性,cocoa,refactoring,Cocoa,Refactoring,我有两个NSResponder方法(cut、copy),它们的代码基本相同,只是它们调用自己的super。如何创建以参数_CMD作为选择器的方法来调用super,而不会以递归结束 - (void)copy:(id)sender { [self notifyAndPerformSelector:_cmd withObject:sender]; } - (void)cut:(id)sender { [self notifyAndPerformSelector:_cmd withOb
- (void)copy:(id)sender
{
[self notifyAndPerformSelector:_cmd withObject:sender];
}
- (void)cut:(id)sender
{
[self notifyAndPerformSelector:_cmd withObject:sender];
}
- (void)notifyAndPerformSelector:(SEL)selector withObject:(id)sender
{
[super performSelector:selector withObject:sender];
//code...
}
正如您所发现的,您的代码并没有像您希望的那样调用超类方法,而是调用当前类中的方法,从而导致无限递归 面对这一点,您的第一个选择是重构代码,大致如下:
@implementation MyDerivedClass
{
- (void)copy:(id)sender
{
[super copy:sender];
[self commonCodeAfterSelector:_cmd withObject:sender];
}
- (void)cut:(id)sender
{
[super cut:sender];
[self commonCodeAfterSelector:_cmd withObject:sender];
}
- (void)notifyAndPerformSelector:(SEL)selector withObject:(id)sender
{
//code...
}
}
如果这种方法适合您的情况,请使用它。如果不是
第二个选择是成为编译器
标准和超级方法调用
表单的标准方法调用:
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
objc_msgSendSuper(`struct` containing `self` and superclass,
@selector("someMethodWithArg1:andArg2:"), x, y)
调用对方法someMethodWithArg1:andArg2:
的搜索。此搜索从对象的运行时类开始。强调运行时很重要,object
引用的实际对象可能与声明的object
类型属于同一类,或者属于该类型的子类,搜索必须找到该方法最派生的实现
以下形式的超级方法调用:
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
objc_msgSendSuper(`struct` containing `self` and superclass,
@selector("someMethodWithArg1:andArg2:"), x, y)
还调用对方法someMethodWithArg1:andArg2:
的搜索。然而,在这种情况下,搜索是从发生代码的类的超类的编译时类开始的。例如,如果上面的MyDerivedClass
是MyBaseClass
的一个子类,那么对该方法的搜索从MyBaseClass
开始,忽略self
的运行时类型–可以是MyDerivedClass
或其子类(比如myderivedERivedClass
)
为什么您当前的代码会递归
您的电话:
[super performSelector:selector withObject:sender];
在超类中开始搜索方法performSelector:withObject:
,该搜索在到达NSObject
类之前不会找到该方法。一旦找到该方法,就会调用该方法并开始标准(非超级)搜索选择器的方法
,此搜索从运行时类型self
开始,并在MyDerivedClass
中查找该方法。。。递归
您需要的是:
[self performSuperSelector:selector withObject:sender];
但不幸的是,这并不存在。但是你可以做一个
编译方法调用
编译器采用以下形式的标准方法调用:
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
objc_msgSendSuper(`struct` containing `self` and superclass,
@selector("someMethodWithArg1:andArg2:"), x, y)
并且有效地(我们对一些细节进行了润色,下面将填写需要的细节)将其编译为对运行时函数的调用objc\u msgSend()
:
请注意,选择器作为SEL
值传递,这是\u cmd
值的来源
以下形式的超级调用:
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
objc_msgSendSuper(`struct` containing `self` and superclass,
@selector("someMethodWithArg1:andArg2:"), x, y)
有效地编译为对以下形式的objc\u msgSendSuper()
的调用:
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
[object someMethodWithArg1:x andArg2:y]
[super someMethodWithArg1:x andArg2:y]
objc_msgSendSuper(`struct` containing `self` and superclass,
@selector("someMethodWithArg1:andArg2:"), x, y)
您可以在自己的代码中直接调用这些运行时函数。您必须导入
以获取定义,并将其转换为适当的类型,等等
成为编译器并绕过执行选择器
您的代码使用performSelector
,因为它有一个SEL
值,但如上所示,用于方法调用的运行时调用直接使用SEL
。如果您自己“编译”超级调用,则不需要使用performSelector
,从而避免了递归问题
在调用objc_msgSendSuper()
之前,需要强制转换函数,以便其返回和参数类型与正在调用的选择器的实际返回和参数类型匹配。这样就可以编译正确的代码来处理参数和返回值,并且代码依赖于类型。您正在调用的两个选择器,copy:
和cut:
,具有相同的类型,使代码更短。为了使铸造更容易,我们首先为类型定义一个速记:
typedef void (*CutOrCopyRunner)(struct objc_super *super, SEL op, id sender);
它将CurOrCopyRunner
定义为函数指针类型。现在您的方法是:
- (void)notifyAndPerformSelector:(SEL)selector withObject:(id)sender
{
// "compile" [super selector:sender];
// first cast objc_msgSendSuper to the correct type by
// casting a function pointer to it (a function name by
// itself, e.g. objc_msgSendSuper, evaluates to a pointer
// to the function)
CutOrCopyRunner msgSender = (CutOrCopyRunner)objc_msgSendSuper;
// now build the first argument struct
struct objc_super superInfo;
superInfo.receiver = self;
superInfo.super_class = MyDerivedClass.class.superclass;
// now execute the super call
msgSender(&superInfo, selector, sender);
// code...
}
HTH我感兴趣的是如何将_CMD作为选择器传递,而不是正确提取此特定代码