Objective-C 和 applescript -> 超时事件和线程

Objective-C and applescript -> Timeout events & threads

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

我有一个实现了 applescript 类 的应用程序,XCode 为我编译了它们。每当我从 *.m 文件(和后台线程!)中调用 applescript 方法时,我 dispatch_sync 将它传递给主线程(因为 applescript 需要在主线程中执行)- sync 因为我需要结果继续。

我想用一个简单的例子给你看:

苹果脚本:

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

// 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 冻结,然后我的整个应用程序冻结,因为它基本上永远在主线程上等待。

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

所以我的问题是:有什么方法可以在 x 秒后停止整个 dispatch_sync 块?或者有没有其他可能保留应用程序 运行 而不是通过 InDesign 冻结永远锁定?

注意:实施工作正常 - 请不要推荐 'use NSApplescript' 或 'use Scripting Bridge'。 原因:ScriptingBridge - 几乎不可能为 InDesign 创建一个有效的 HEADER 文件(它几乎重 15 MB 并抛出大量编译器错误 - 我确实通过大量手动工作修复了一次只是为了看到它不再适用于下一个版本在设计中)。只要您有简单的脚本,NSApplescript 就可以,但事实并非如此。

感谢任何帮助

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

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

..

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

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


  • p.s。 ASOC 的另一个问题是 10.13 的 bridgesupport 文件中的更改有 changed/broken C API 映射到 AS 的方式,这可能会破坏现有的基于 ASOC 的脚本。 (我已经停止推荐 ASOC unless/until,这是固定的。)