Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa 如何重构调用super的代码中的重复性_Cocoa_Refactoring - Fatal编程技术网

Cocoa 如何重构调用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

我有两个NSResponder方法(cut、copy),它们的代码基本相同,只是它们调用自己的super。如何创建以参数_CMD作为选择器的方法来调用super,而不会以递归结束

- (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作为选择器传递,而不是正确提取此特定代码