【发布时间】:2020-05-25 17:06:13
【问题描述】:
上下文:我正在处理a Pharo/Smalltalk -> Objective-C bridge
场景:在下面的Objective-C ScriptingBridge sn-p中:
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
iTunesTrack *currentTrack = iTunes.currentTrack; //[1]
// This low level way works too
//iTunesTrack *currentTrack = [iTunes propertyWithCode: 'pTrk']; //[2]
[iTunes playpause]; //[3]
问题:桥使用class_getInstanceMethod 来确定对象是否理解消息/选择器,但对于像playpause 这样的脚本消息,它返回NULL
问题 #1
为什么class_getInstanceMethod 对像playpause 这样的脚本消息返回NULL? class_copyMethodList 有同样的问题吗?脚本消息的作用与其他 Obj-C 消息不同(除非它们这样做!),有什么特别之处?
问题 #2 [已解决 - 请参阅 @Matt 的回答]
根据the docs,在“为 iTunes 应用程序动态定义的子类”中,SB 将“自动处理 Apple 事件发送的特定于应用程序的方法”放在哪里?而且,鉴于class_getInstanceMethod 无法找到这种行为(见下文),桥接测试它的可靠方法是什么(即是否存在这样的方法/消息)?
Objective-C 运行时 API 报告混合结果。一方面,iTunesApplication 类似乎没有任何方法(或属性):
-
class_copyMethodList([iTunes class]...返回零个方法 -
网桥用于查找和执行方法的
class_getInstanceMethod失败。
另一方面,#playpause 可以通过 API 的其他部分进行查询和发送:
-
respondsToSelector:-> 是的 -
methodSignatureForSelector:返回签名 - 和
performSelector:实际发送消息
奇怪的是,methodForSelector:@"playpause" 在 Obj-C 中成功返回了 IMP,但如果从桥的另一端发送则会崩溃。
问题 #3 [已解决]
如何模拟/复制 [3]?
@Willeke 在 cmets 中回答:[iTunes sendEvent:'hook' id:'PlPs' parameters:0]
【问题讨论】:
-
我不确定我是否理解这个问题。
[iTunes playpause]的“低级方式”是[iTunes sendEvent:'hook' id:'PlPs' parameters:0]。[iTunes propertyWithCode: 'pTrk']返回SBObject*,[iTunes propertyWithClass:[self.iTunes classForScriptingClass:@"track"] code:'pTrk']返回iTunesTrack*。 -
@Willeke 如果我找不到答案,这已经很有帮助了。我的问题归结为:我如何访问例如如果 Obj-C 运行时反射 API 似乎看不到该方法,则从桥的另一端“为 iTunes 应用程序动态定义的子类的 currentTrack 方法”? SB 在哪里“隐藏”这些动态实现的方法/属性?我宁愿以某种方式从 Smalltalk 中调用“playpause”,而不是使用类似于您提供的代码重新实现它
-
为什么不研究一个替代的开源桥来看看它是如何完成的呢?看看 appscript 等。警告,这里是龙。如果这很容易,其他人就会做到。
-
啊,好吧,对不起,我对 Pharo 或
class_getInstanceMethod一无所知。但是 appscript 是开源的,所以正如我所说,如果你想知道它是如何工作的,你可以自己看看。抱歉,我只能提供这些了。 -
因为您首先从物理上生成一个基于 iTunes 字典 (sdef) 的 iTunes 类,其中声明了
playpause。它是一个 SBApplication 子类。天哪,很抱歉我删除了我之前的评论。
标签: objective-c smalltalk pharo objective-c-runtime scripting-bridge