swift - 如何在swift中进行函数回调
问题描述
在开始之前,我知道有很多与此类似的问题。但是,我认为 swift 的较新版本可能使它们过时了,因为它们似乎对我不起作用。
这是我的问题:我需要将一个函数作为参数传递给另一个函数(回调)。但是,我无法弄清楚如何在 Swift 5.3.3 中执行此操作(我很确定这是我的版本)
我想制作一个 Mac 应用程序来控制我的许多不和谐机器人中的哪些正在运行。我的不和谐机器人是执行永无止境的 python 文件。因此,如果我使用 swift 的 shell 执行它们,那行代码将永远不会结束。因此,我想异步执行每个机器人,这样应用程序就不会冻结。我目前正在通过制作DispatchWorkItem
, 然后DispatchQueue.main.async(execute:DispatchWorkItem)
用于执行机器人来做到这一点。但是,制作 aDispatchWorkItem
需要回调函数来执行(我忽略了其他看似可选的参数)。
这就像我正在尝试做的事情:
let workItem=DispatchWorkItem(**INSERT CALLBACK(to exec function defined below) HERE**)
DispatchQueue.main.async(workItem)
我还没有让它成功运行。我几乎没有 swift 方面的经验,所以我对自己做错了什么没有一个超级坚定的想法。该代码中应该用什么\*\*INSERT CALLBACK(to exec function below) HERE\*\*
替换?如果您需要更多信息,请告诉我。
谢谢!
以下是我的代码的所有相关部分:
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
//for the record I did not write that function(got it from this site) and sort of vaguely understand it but not really
func exec(){
let result = shell("/usr/local/bin/python3.9 path/to/python/file")
print(result)
}
//this has been proven to work, it just freezes that app because the above function will never end. This is why I want it to be asynchronous
解决方案
与其直接回答,我首先想向您简要介绍一下回调函数。
简而言之:在大多数现代编程语言中,函数可以作为另一个函数中的参数/参数:
function doHomework(subject, finishedHomework()) {
print('Started my homework!');
}
在上面的简化案例中,doHomework 是开始执行之前的回调函数(finishedHomework)。如果我们这样称呼它:
doHomework('IT', () -> { print('Finished my homework!); });
或者
finishedHomework() { print('Finished my homework!') }
doHomework('IT', finishedHomework);
我们将看到一个输出,说我们已经开始在第一行打印出我们的作业,并且我们已经在下面的行中完成了我们的作业。我把它放在一行上,这样你就可以看到括号是如何等同的。我们这样做是因为在我们的第一个函数执行延迟的情况下(即 API 调用、复杂计算),它仍然会先执行,然后按该顺序执行第二个函数。将回调的执行视为依赖于初始函数;如果我们开始做作业,但发生其他事情阻止我们,我们就不会完成它。
在 Swift 中,我相信回调也被称为闭包函数,通常与完成处理程序配对,为了简单起见,我不会过多介绍。这是另一个例子,但这次是在 Swift 中传递一个值:
let closureFunction = {
(x: Int) -> String in
return "The number in our closure function is: \(x)."
}
func funky(callback: (x: Int) -> String) {
callback(13)
}
funky(closureFunction) /** The number in our closure function is: 13. */
请记住,在 Swift 5 中,我们仍然可以定义如下函数:
(String)->() // takes a String returns void
()->(String) // takes void returns a String
闭包语法通常采用以下形式:{ (parameters) -> return type in statements }
免责声明:我没有在下面测试过这段代码,但希望它是朝着正确方向迈出的好一步。
let shell = {
(_ command: String) -> String in
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
func exec(callback: (command: String) -> String) {
let result = callback("/usr/local/bin/python3.9 path/to/python/file")
print(result)
}
exec(shell)
我对使用 DispatchWorkItem 不熟悉,所以可以考虑学习关于 DispatchQueue 基础知识甚至 DispatchSemaphore 的快速教程。无论哪种方式,我认为这应该足以让您获得足够的信息来进行机器人管理,而无需让某人为您完成工作。从这里将回调添加为 DispatchQueueItem 应该很容易。
让社区知道您是否仍然面临问题。
推荐阅读
- c# - 消歧:为 Windows Explorer.exe 的上下文菜单编写 Shell 扩展与在您的应用程序中使用 Shell ContextMenu
- java - 单击导航到新活动的按钮图标后,Android 应用程序崩溃
- makefile - makefile 通配符先决条件多次获取同一个文件
- c# - 如何解决我将字符串转换为日期时间的问题?
- javascript - 如何翻译调整大小的画布?
- javascript - 幻灯片中的滑块之前和之后
- r - 如何查看列表中的哪个元素(长度为 x)包含在该列表的哪个其他元素(长度为 x+1)中?
- git - 如何让我的本地 git 安装默认为主分支而不是主分支?
- sql - 如何删除日期太近的记录?
- vba - 如何使用宏和 vba 重命名 PowerPoint 中的部分