当我尝试调用另一个静态异步函数并声明在主要参与者上运行时,我的参与者遇到了问题。具体来说,被调用函数执行到最后,但似乎永远不会将执行控制权返回给调用者(我的演员)。
这导致函数调用后的代码永远不会执行。
简单来说,看起来正在执行的 MainThread 只是简单地“吞噬”了 return 语句。
下面是我的代码(结构上)的一个最小示例。在被调用函数中实际发生的是
ScreenCaptureKit
调用。为了清楚起见,我决定把它们留在里面。
actor SomeActor {
func myTestFunction() async throws {
print("Before execution")
let returnValue = try await SomeClass.createSCKSnapshot()
print("After execution") // this is never called since the previous await never seems to return execution back to SomeActor
}
}
@MainActor
class SomeClass {
@MainActor public static func createSCKSnapshot() async throws -> (displays: [SCDisplay], windows: [SCWindow], applications: [SCRunningApplication]) {
let shareableContent: SCShareableContent = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: false)
return (shareableContent.displays, shareableContent.windows, shareableContent.applications)
}
}
现在,在这里你看到我的演员
SomeActor
试图在它的一个孤立函数中调用 SomeClass.createSCKSnapshot()
。因此,createSCKSnapshot()
执行得很好,包括 return 语句,但是没有任何反应并且 print("After execution")
永远不会在 SomeActor
. 中执行
为什么?以及如何绕过这个问题并确保我的程序在
createSCKSnapshot()
返回后继续正常执行?
编辑:
应用程序确实有权限并在应用程序的各个位置使用ScreenCaptureKit,一切正常。唯一的区别是来自这些位置的代码不是从 actor 内部调用方法,而是从类中调用方法。因此,我相信这一定是演员的某种问题。
考虑:
func myTestFunction() async throws {
print("Before execution")
let returnValue = try await SomeClass.createSCKSnapshot()
print("After execution")
}
有两种可能:
第一次尝试此操作时,
SCShareableContent.excludingDesktopWindows
将暂停,直到用户响应系统对话消息。
如果用户拒绝许可,应用程序的后续启动将不会导致看到“执行后”消息(更不用说屏幕录制弹出消息)。将抛出一个错误,并且在
try
行之后什么也不会执行。第二个 print
声明将无法实现(尽管 myTestFunction
会返回)。
FWIW,在边缘情况下(我在 Ventura 13.3.1 中遇到过,但无法重现)
excludingDesktopWindows
暂停,但它的延续永远不会恢复。没有线程/actors 被阻塞,但是在await
之后,它永远不会继续执行。这种奇怪的行为似乎已通过重新启动我的计算机(!)得到解决。