gpt4 book ai didi

objective-c - cocoa 脚本: Intercept any Object-first message calls

转载 作者:行者123 更新时间:2023-12-03 17:10:01 24 4
gpt4 key购买 nike

我正在围绕 Cocoa Scripting 编写自己的非 ObjC 框架(想象一下用 C、C++ 或 Java 编写一个可编写脚本的 Mac 应用程序,或者在我的例子中是 Xojo)。

我希望能够拦截任何对象优先的方法调用,而不必将实际方法添加到 ObjC 类(我不能,因为框架不知道应用程序代码可以提前处理哪些消息 -因此,一旦命令消息从脚本引擎传入,它就必须接收并传递它们)。

例如,任何属性 getter 和 setter 都可以通过实现来拦截

-valueForUndefinedKey:
-setValue:forUndefinedKey:

以及NSScriptKeyValueCoding协议(protocol)的所有方法。

我正在寻找类似的方法来拦截发送到这些 sdef 元素中指定的方法的 NSCommandScript 消息:

<responds-to command="reload">
<cocoa method="reloadList:"/>
</responds-to>

因此,我想知道是否有一种通用方法来捕获所有此类调用,而不是通过将其添加到类方法来实现 reloadList:

我发现类方法

+ (BOOL)resolveInstanceMethod:(SEL)sel

被调用,请求reloadList:。但是同样的方法也会被调用用于许多其他目的,所以我宁愿不盲目地拦截每个这样的调用,因为如果我将它们全部转发给一个告诉我是否想要的 Java 函数,则会导致相当严重的性能损失。例如,处理它。

我希望有一些东西可以让我在进一步转发之前知道该选择器与 NSScriptCommand 相关。

最佳答案

在指定的命令处理方法中设置断点后,我看到了以下堆栈跟踪:

#0  0x00000001000197db in -[SKTRectangle rotate:]
#1 0x00007fff8ee0b7bc in __invoking___ ()
#2 0x00007fff8ee0b612 in -[NSInvocation invoke] ()
#3 0x00007fff8eeab5c6 in -[NSInvocation invokeWithTarget:] ()
#4 0x00007fff8b82cbde in -[NSScriptCommand _sendToRemainingReceivers] ()
#5 0x00007fff8b82cf39 in -[NSScriptCommand executeCommand] ()

这表明 NSScriptCommand 似乎没有使用任何可定制的特殊转发机制,而是使用 NSInitation 来调用该方法。

此类调用可以这样拦截:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
// Look for signatures with exactly one ":"
if ([[NSStringFromSelector(aSelector) componentsSeparatedByString:@":"] count] == 2) {
return [NSMethodSignature signatureWithObjCTypes:"@:@@"];
} else {
return [super methodSignatureForSelector:aSelector];
}
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
id arg; // The first and only argument is expected to be of type NSScriptCommand*
[anInvocation getArgument:&arg atIndex:2];
if ([arg isKindOfClass:[NSScriptCommand class]]) {
NSLog(@"executing the command...");
// when finished, set the return value (which shall be an NSObject)
id result = nil;
[anInvocation setReturnValue:&result];
} else {
// oops - we cannot handle this
[super forwardInvocation:anInvocation];
}
}

这种形式的拦截比使用 resolveInstanceMethod: 效果更好,因为它不会被频繁调用,而是仅用于特定目的,例如 NSScriptCommand 执行。

然而,这样做的问题是,如果其他代码也使用 NSInitation 出于其他目的对同一类进行调用,并且如果这些调用使用匹配的选择器签名,则上面的代码将拦截这些调用,然后不处理它们,可能会导致意外的行为。

只要已知这些类仅由脚本引擎使用并且没有其他行为(即它们是 NSObject 的直接子类),就没有理由发生这种情况。因此,在我的特殊情况下,类仅充当另一个环境的代理,这可能是一个可行的解决方案。

关于objective-c - cocoa 脚本: Intercept any Object-first message calls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36264669/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com