Reputation: 529
I am making a macOS app. I have a task (a script) that I am running with Process()
in Swift 3. When I press a button (button.State == NSOnState
), I would like the task to repeating n times, and terminate earlier until the button is pressed again (button.State == NSOffState
).
I looked up how to repeat a task, and it looks possible with a simple for
loop – for i in {1..n}
.
Now, the problem I am having is that it doesn't seem to be possible to call a task multiple times. When I try to call the task the second time, I get an error in the console:
[General] task already launched
Here is my code:
@IBAction func buttonPressed(_ sender: Any) {
let script = "for i in {1..5}; do echo \"hi\"; done; sleep 1"
let task = Process()
task.terminationHandler = self.commandTerminationHandler
task.launchPath = "/bin/bash"
task.arguments = ["-c", script]
if button.state == NSOnState {
task.launch() // launches task
task.waitUntilExit() // waits until task has been completed (about 1 second)
task.terminate() // (should) terminate the task. (The console error occurs with or without this line)
task.launch() // tries launching the task again, but this results in the console error.
print("The task was launched twice")
} else {
// task.terminate()
}
}
I googled this error, and found [this][https://forums.macrumors.com/threads/nstask-not-terminating.1617855/#post-17677541]:
The error isn't that the task is still running. It's that the task has already run and completed, and can't be started again. You'll need to create a new NSTask object to run the task again.
So I need to make a new NSTask
(or Process
as of Swift 3) and keep making new ones to repeat the code forever. This sound very complicated (as if I'm using a workaround) and is probably inefficient.
Is there a better way to repeat a Process in Swift 3?
For the sake of completeness, I'd also like to mention that I considered using for i in {1..n} do ... done
directly in script
. This has one problem:
task.terminate()
, I get the error "task not launched." The only way I can stop it is by running killall bash
in my Terminal, which doesn't seem like a nice solution. To do this in Xcode, I'd need make a Process to kill bash with bash... which is strange.Upvotes: 3
Views: 1534
Reputation: 16
For anyone still facing this issue @kmarwah's solution works just fine, even in Swift but with one small modification. So instead of setting task (Process
) to nil
, just initialize it again. Take a look at this example:
var task = Process()
...
task.terminate()
task = Process()
Upvotes: -1
Reputation: 53
If you set your task item to a var instead of a let you can repeatedly set task to a new process object inside your loop.
var task = Process()
task.launchPath = ....
task.arguments = [...]
task = Process()
task.launchPath = ....
task.arguements = [...]
Upvotes: 1
Reputation: 78
I'm having the same issue. A potential fix that I've come across online is to set the task to nil
after terminating it, then reassigning parameters such as path, arguments, etc before running it again. However this can only be done in Objective C; Swift has very strict rules when it comes to nil
(and probably for good reasons).
Upvotes: 1
Reputation: 11
You can run 2 different script at the same time. One of them you want to run should be running and the other always check the another script at every turn and this should be like recursive. The another script will kill the another script until the button is pressed.
Upvotes: 0