关于多线程:Objective-C 和 applescript -> 超时事件

Objective-C and applescript -> Timeout events & threads

我使用的是 macOSX (Sierra),而不是 iOS、Objective-C、Xcode9。

我有一个带有已实现的 applescript 类的应用程序,XCode 为我编译它们。每当我从 *.m 文件(以及后台线程!)中调用 applescript 方法时,我将它 dispatch_sync 到主线程(因为 applescript 需要在主线程中执行) - 同步原因我需要结果才能继续。

我想用一个简单的例子告诉你:

Applescript:

1
2
3
4
5
6
7
8
9
on openFile_filePath(filePath)
    try
        tell application"Adobe InDesign CC 2018"
            set myDoc to open (filePath as string)
            return id of myDoc
         end tell
    end    
    return 0
end

Objective-C

1
2
3
4
5
6
7
// Method is running in a background thread
// appleScriptHelper is properly instantinated
__block NSInteger docID = 0;
NSString* someFile = @"/Users/user/Desktop/";
dispatch_sync(dispatch_get_main_queue(), ^{
    docID = [self.appleScriptHelper openFile:someFile];
});

这运行顺利 - 只要 InDesign 响应!有时,InDesign 冻结,然后我的整个应用程序冻结,因为它基本上在主线程上永远等待。

我尝试了什么:
我不能使用计时器,因为无论如何主线程都被阻塞了,而且我不能传递"取消"消息——因为 Applescript 一直很忙,等待永远不会发生的事情。
此外,当从 XCode 编译时,无法在 applescript 中使用"超时 x 秒"(就像其他帖子中提到的那样不起作用)。
我用 NSOperations 尝试过,但因为我需要分派到 mainThread ......仍然是同样的问题。

所以我的问题是:有什么方法可以在 x 秒后停止整个 dispatch_sync 块?或者是否有任何其他方法可以通过 InDesign 冻结来保持应用程序运行并且不会永远被锁定?

注意:实现工作正常 - 请不要推荐\\'use NSApplescript\\' 或\\'use Scripting Bridge\\'。
原因:ScriptingBridge - 几乎不可能为 InDesign 创建一个有效的 HEADER 文件(它几乎有 15 MB 的大小并引发大量编译器错误 - 我确实通过大量手动工作修复了这个问题,只是为了看到它不再适用于InDesign 的下一个版本)。只要你有简单的脚本,NSApplescript 就可以了。

任何帮助表示赞赏


如果 NSAppleScript 足以满足您的需求,我会说使用 NSUserAppleScriptTask,它使用异步完成回调在进程外运行脚本。是的,正如您所说,Scripting Bridge 完全不适合重要的自动化,尤其是任何涉及 Adob??e 等大型复杂硬壳 Carbon 应用程序的应用程序,所以不要在这上面浪费一秒钟。

有 AppleEventBridge/SwiftAE,但随着 Apple 洗牌整个 AS/AE 基础设施以悄然消亡,我不再推广或支持它们,所以 maxima 告诫购买者。 (我仍然使用 Python appscript 来实现我自己的 Adob??e 应用程序自动化,顺便说一句,它继续把其他一切都吹得一团糟,但如果整个行业最终将 Windows 作为唯一的面向专业的平台留下来,我不会感到惊讶。 )

..

使用 AppleScript-ObjC* 的问题在于 AppleScript 组件(也称为解释器)实例不是线程安全的:您可以在您喜欢的任何线程上实例化它们,但您只能在该线程上使用它们,而不能在其他线程上使用它们。 ASOC 不允许您自己控制任何这些东西; NSAppleScript 也没有。 (OSAKit 可以,但使用起来和 NSAppleScript 一样痛苦。)因此 ASOC 代码实际上仅限于在主线程上运行。

如果您坚持使用 ASOC,我认为您最好的办法是将该代码推送到您的主进程通过 XPC 服务或其他方式异步与之对话的子进程中。这将避免阻塞主进程的主事件循环(然后阻塞它的 GUI),同时允许 ASOC 独立地做自己的事情。

  • p.s. ASOC 的另一个问题是 10.13 的 bridgesupport 文件中的更改已经更改/破坏了 C API 映射到 AS 的方式,这可能会破坏现有的基于 ASOC 的脚本。 (我已经停止推荐 ASOC 除非/直到它修复。)