【问题标题】:Obj-C introspection: How can a method reference arguments it's called withObj-C 内省:方法如何引用它调用的参数
【发布时间】: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


【解决方案1】:

关于获得NSInvocation,首先想到的是您无法实现该方法,然后将使用正确构造的NSInvocation 调用-forwardInvocation:。但我想这并没有直接帮助,因为您需要实现该方法并在该方法中做一些事情。但是,也许您可​​以在-forwardInvocation: 中做的是调用另一个对象的调用(“转发调用”),该对象上的方法会执行真正的操作。然后,您还可以将调用存储在该方法可以在必要时访问的某个位置。或者,也许您可​​以在 -forwardInvocation: 本身中执行您想要的“重新运行”逻辑。

【讨论】:

  • 是的,NSProxy 或 NSObject 作为代理。它确实在我脑海中浮现,是一个漂亮、干净的设计。但是,我仍然想研究一种使用宏的方法,并找出在技术上是否可以研究任何 Obj-C 方法中的任意参数,尤其是当 _cmd 如此轻松地为您提供选择器时。但是,如果没有其他答案,我会接受这个,因为它最接近我的设计目标,即重复代码很少(因此是维护/调试的噩梦)。
  • 更正 - “NSProxy 或 NSObject 子类作为代理”
猜你喜欢
  • 2012-01-15
  • 2010-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多