返回大值的 NSUserAppleScriptTask 从不调用 completionHandler

NSUserAppleScriptTask returning large value never calls completionHandler

我有一个 Objective-C 应用程序正在使用 NSUserAppleScriptTask 调用一些 Applescript。 applescript 是 return 一个可以改变大小的字符串。

它在字符串很短的情况下工作正常。然而,当它变得很长时,它开始无声地失败。如果它尝试 return 一个长度为 40,000 个字符的字符串,则永远不会调用 completionHandler,并且永远不会打印字符串 returned ...。没有消息到日志,没有消息到控制台。它只是从未被调用过。

30,000 个字符的字符串可以正常工作。我不确定精确的截止点在哪里。

有人以前看过这个吗?我可以更改 属性 或配置设置以增加此限制吗?还是我只需要放弃 NSUserAppleScriptTask?

代码

NSURL* scriptURL = [[NSBundle mainBundle] URLForResource:@"ApplescriptHelper" withExtension:@"scpt"];
NSError* error;
NSUserAppleScriptTask* task = [[NSUserAppleScriptTask alloc] initWithURL:scriptURL error:&error];
NSLog(@"created task %@, error %@", task, error);

/* CREATE APPLE EVENT */
// taken from https://www.objc.io/issues/14-mac/sandbox-scripting/
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];

NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"test"];

NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
[event setParamDescriptor:function forKeyword:keyASSubroutineName];
/* END CREATE APPLE EVENT */

[task executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor*resultEventDescriptor, NSError *error) {
    NSLog(@"returned %@, error %@", resultEventDescriptor, error);

    if (!resultEventDescriptor) {
        NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
    } else {
        NSLog(@"success")
    }
}];

ApplescriptHelper.scpt

on test()
    set str to ""
    repeat 40000 times
        set str to str & "x"
    end repeat
    return str
end fetchMusic

这看起来像是一个 Apple 漏洞。你应该提交一份报告。

运行 您的代码,osascript 停滞于以下调用图:

+ 2812 start  (in libdyld.dylib) + 8  [0x7fff97a205b4]
+   2812 exit  (in libsystem_c.dylib) + 55  [0x7fff9157f403]
+     2812 __cxa_finalize_ranges  (in libsystem_c.dylib) + 345  [0x7fff9157f0ff]
+       2812 std::__1::ios_base::Init::~Init()  (in libc++.1.dylib) + 16  [0x7fff8f1ebd98]
+         2812 std::__1::basic_ostream<char, std::__1::char_traits<char> >::flush()  (in libc++.1.dylib) + 68  [0x7fff8f1e2f5a]
+           2812 std::__1::__stdoutbuf<char>::sync()  (in libc++.1.dylib) + 137  [0x7fff8f1ec30d]
+             2812 fflush  (in libsystem_c.dylib) + 40  [0x7fff9155c31c]
+               2812 __sflush  (in libsystem_c.dylib) + 87  [0x7fff9155c3c0]
+                 2812 _swrite  (in libsystem_c.dylib) + 87  [0x7fff91563e96]
+                   2812 __write_nocancel  (in libsystem_kernel.dylib) + 10  [0x7fff918e57ba]

我认为您 运行 喜欢 pipe buffer limit of 65536 bytes

如果您使用 NSUserAppleScriptTask 使用的未记录的 osascript 参数,您将获得带有 16 字节 header 和 UTF-16 编码文本的原始 AppleEvent 输出。

repeat 循环中超过 32760 的任何内容都会导致此行为。 32760 * 2 + 16 = 65536.