Objective-C bridge 场景:在以下 Objective-C ScriptingBridge 片段中: iTunesAppl-6ren">
gpt4 book ai didi

objective-c - ScriptingBridge - 它是如何工作的 "Behind the Scenes"

转载 作者:行者123 更新时间:2023-12-04 01:25:29 25 4
gpt4 key购买 nike

上下文:我正在处理 a Pharo/Smalltalk -> Objective-C bridge

场景:在以下 Objective-C ScriptingBridge 片段中:

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"成功返回 IMP在 Obj-C 中,但如果从桥的另一侧发送,则会崩溃。

    问题 #3 [已解决]

    如何模拟/复制 [3]?

    @Willeke 在评论中回答: [iTunes sendEvent:'hook' id:'PlPs' parameters:0]

    最佳答案

    If SB doesn't use Objective-C messages, what do the docs mean by "subclasses of SBApplication implement application-specific methods that handle the sending of Apple events automatically"? Why does iTunes respondsToSelector: @"playpause" work i.e. return true? And how does [iTunes playpause] work? Etc, etc..



    它之所以有效,是因为您在脚本桥接应用程序中所做的第一件事就是生成一个 header 。在 Catalina 中,您可以这样做:
    sdp -f h --basename iTunes /System/Applications/Music.app/Contents/Resources/com.apple.Music.sdef

    这将读取 iTunes 字典 ( sdef ) 并为一组类似的 Objective-C 类生成 header 。现在您有一个 iTunes.h 文件,您将其包含在应用程序项目中并导入您的代码中。它包含这一行:
    - (void) playpause;  // toggle the playing/paused state of the current track

    所以现在 playpause明确声明为合法命令,您可以将其发送到 iTunesApplication 对象。然后,当您实际运行应用程序时,您会说
    iTunesApplication* tunes = (iTunesApplication*)[SBApplication applicationWithBundleIdentifier:@"com.apple.music"];

    这会导致您的应用程序与 iTunes (Music) 对话并再次获取字典 ( sdef ),从而为 header 中声明的方法生成实现。 playpause 的实现命令正是 sdef说的应该是:即发送 hookPlPs事件到 iTunes。

    所以这就解释了为什么你可以说 playpause当你说出来时会发生什么。

    这就是 AppleScript 的本质——它是一个应用程序,它提供了您可以使用 Apple 事件对它说的话的列表,以及引用这些 Apple 事件的类似英语的术语。

    所以如果你想写一个桥梁,你必须做同样的事情:你需要提供一种方法来冲刷 sdef目标应用程序的资源,并将该信息转换为以您的语言给出相应命令的方式,无论它是什么。

    关于objective-c - ScriptingBridge - 它是如何工作的 "Behind the Scenes",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62007277/

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