【发布时间】:2013-04-26 23:57:09
【问题描述】:
这是问题的故意“分叉”: Obj-C introspection: How can a method reference its own selector?
我需要做与 OP 完全相同的事情,但他不需要传递任何参数,但我需要。
我已经有一种方法可以调用具有多个未知参数的方法(NSInvocation)。我有一些方便的方法可以帮我做这件事,比如question。但是,必须为每个需要这样做的类中的每个方法重复工作,这会导致维护问题,并且当错误的参数(或以错误的顺序)传递给便捷方法时会出现地狱般的调试。
这本身是一个相对较小的问题,但我已经解决了两年,并希望解决这个问题。通过使用单行宏(如@Michael57)来调用我的便捷方法,自动检查选择器(使用 _cmd)和参数(使用?)并按照我的意愿调用便捷方法。
请注意,这适用于具有固定参数列表而不是可变参数的方法。所以我不确定 va_args 方法是否适用于检查参数。
因此,无论是从代码管理的角度来看,还是纯粹出于技术上的好奇(如果选择器存在 _cmd,那么参数肯定有一些东西?)我想知道如何内省标准的 Obj-C 方法参数。
我希望这是我所缺少的非常明显的东西。谢谢您的帮助!
编辑:一些示例代码:
我尝试做的基本目的是始终在单个线程中运行在某个实例上调用的方法。为此,我在 NSObject 类别中有一个方便的方法:
- (void)performSelectorInBackground:(SEL)aSelector waitUntilDone:(BOOL)waitUntilDone withArgumentLocations:(void *)firstArg,...;
它在专门映射到该实例的特定后台线程中的目标对象上运行被调用的选择器。所有这些只是为了避免一些否则会发生的粘性同步问题。
也许这一切一开始都是笨拙的,但我已经过去了。这段代码集成在太多地方。 :)
“withArgumentLocations”可变参数列表是一个指针位置列表,它可以接受标量值和常规 Obj-C 对象,因此在后台调用具有可变数量和类型的参数的选择器的常规任务是简单的 1 线事务。
无论如何,一个实际的用例如下:
- (void)loginRequestWithUsername:(NSString *)username andPassword:(NSString *)password {
if(![self isInBackgroundThread])
{
[self performSelectorInBackground:@selector(loginRequestWithUsername:andPassword:) waitUntilDone:NO withArgumentLocations:&username, &password, nil];
return;
}
[self isInBackgroundThread] 是另一种方便的方法,它检查当前执行线程是否是此实例的“分配”线程。
所以这种方法对于单独的方法调用效果很好,但现在我想将它扩展到一个类中的所有方法。当“argumentLocations”未正确替换或未按正确顺序等时,这有时会导致问题,从而导致地狱般的调试。
这就是为什么我想用一个小宏替换上面的代码块,我可以简单地将它粘贴到每个方法中来实现我需要的。
这就是为什么这个宏应该能够查询它自己的选择器 (_cmd) 和参数(使用 ?)并将它们传递给我的 performSelectorInBackground:waitUntilDone:withArgumentLocations: 方法。
【问题讨论】:
-
我在调查期间确实遇到了这个答案,但这并没有帮助。我已经有了这些方法来为我做这些肮脏的工作。我的问题不是为每种方法重复参数包装、调用等。我想要的是能够创建一个宏,这样我的每个方法的代码维护成本只有 1 行,因此需要参数自省。我已经有了“几乎就在那里”的调度程序代码。
-
@matt 实际上我刚刚意识到我的问题并没有完全阐明我的这部分要求(我有肮脏的工作方法,我只需要想办法将它们进一步压缩到一个单行宏,用于代码维护问题)。我会稍微编辑一下这个问题。感谢您的提示。
-
我认为如果你给出一个实际的例子会有所帮助。传入的示例方法调用是什么,您尝试输出的方法调用是什么?
-
看这个:mikeash.com/pyblog/… ...在我看来,你必须降到汇编语言的水平。也许使用
forwardInvocation:会更好,因为它会为您收集参数值!
标签: ios objective-c selector introspection objective-c-runtime