Swift: command line tool exit callback - swift

I need to know when a command line program is stopped by the user to release some active bluetooth connections from a command-line program (running on the terminal), written in swift.
Say the user calls the program then exits by pressing ctrl+Z.
How would I know ?

You can install a signal handler with Swift. For example:
import Foundation
let startTime = Date()
var signalReceived: sig_atomic_t = 0
signal(SIGINT) { signal in signalReceived = 1 }
var i = 0
while true {
if signalReceived == 1 { break }
usleep(500_000)
if signalReceived == 1 { break }
i += 1
print(i)
}
let endTime = Date()
print("Program has run for \(endTime.timeIntervalSince(startTime)) seconds")
Modified from this gist.

Related

Swift - for loop statement not taking an absolute value

Such a weird question, but I set up this code in a playground:
let currentNumber = "1999999999"
let absNumber = abs(Double(currentNumber)!)
var digitCount = 0
if absNumber > 999999999 {
for n in currentNumber {
if n.isNumber {
digitCount += 1
} else {
break
}
print(digitCount)
}
}
As written, this code gets evaluated and my for loop runs...however, if is set my string to "-1999999999", the for loop doesn't run. The absolute value of -1999999999 is 100% greater than 999999999, so what did I miss?
The thing you did not understand is the control flow operator. You can get the expected behavior just change a single line:
if n.isNumber {
digitCount += 1
} else {
break // here change to continue
}
to this:
if n.isNumber {
digitCount += 1
} else {
continue
}
However, I highly recommend you try LLDB in an Xcode Project, either a Commandline tool or app. The stepover tool is quite useful for such a logical problem.

Combine if statement and for loop such that loop only gets executed once per every execution of if statement in swift

I'm trying to understand swift and therefore try to come up with simple command line games: in this game a player has to guess a secret word within 6 attempts by typing something in the command line, but every time he gets it wrong, a statement prints the number of his wrong attempts:
let response = readLine()
if response != "secret word" {
for n in 1...6 {
print(n)
}
}
else {
print("you are right!")
}
Now I know that my code will print all lines once the condition is not true, but I'm looking for a way to only print one item out of the four loop for every if statement consecutively.
I think a while loop works pretty well. Maybe something like this:
print("Welcome to the input game!\n\n\n\n")
var remainingTries = 5
let dictionary = ["apple", "grape", "pear", "banana"]
let secretWord = dictionary.randomElement()
print("Please guess a fruit")
while remainingTries > 0 {
remainingTries -= 1
let response = readLine()
if response == secretWord {
print("You got it!")
remainingTries = 0
} else if remainingTries <= 0 {
print("Too bad, you lose!")
remainingTries = 0
} else {
print("Incorrect. Tries remaining: \(remainingTries)")
}
}

Having trouble with a while loop in Swift 5

Essentially, I'm making an app about a virtual dog to help people take care of their dogs. One of the screens gives you fifteen seconds to pet the dog five times. Whenever I try to load the screen, the app freezes. The code is inside of viewDidLoad()
while timesPetted < 5 {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
timer += 1
if timer == 15 {
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}
})
}
When I delete the while loop, the screen loads normally and runs perfectly, but (obviously) there isn't a time limit. If I move the while loop out of viewDidLoad(), I get an error saying that Xcode "Expected declaration".
Either use a timer that is set to expire in 15 seconds
let timer = Timer.scheduledTimer(withTimeInterval: 15.0, repeats: false) { timer in
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}
Or if you want to use DispatchQueue then use it only once
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}
it appears the while loop is running infinitely due to the value of timesPetted. As the value of timesPetted is not changing at all once it enters the while loop.
To solve your issue you can make changes to your code as below :-
You must be updating your timesPetted value some where in the code.
lets say timesPetted is changed in function called "Petting", so when this function is called have check, which limits the user to pet till 5 times only and another check for 15 seconds. As shown below.
func petting() {
if reset.isHidden && timesPetted <= 5{ // here the reset.isHidden will become false in DispatchQueue (present in viewDidLoad) once the 15 seconds have been passed.
timesPetted += 1
}
}
And also make sure to add this line of code in your viewDidLoad.
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
self.failureLabel.isHidden = false
self.reset.isHidden = false
self.timesPetted = 0
}

fatal error with a simple swift program

import UIKit
import Foundation
func randomnumber (low:Int,high:Int )->Int
{
let range = high - (low-1)
return (Int (arc4random()) % range ) + ( low - 1)
}
let answer = randomnumber(low: 0, high: 100)
var turn = 1
while (true)
{
print ("Guess #\(turn): enter a number between 0 and 100")
let userinput = readLine();
if let guess:Int = Int(userinput!)
{
if( guess<answer )
{
print("choose a higher number")
}
if ( guess>answer )
{
print ("choose a smaller number")
}
if( guess==answer)
{
print("wohoo you won")
break;
}
}
}
this code is about a simple game using swift , by having a random number and then putting an input and if this input is bigger than the random number we have to choose smaller number and the opposite if we choose a smaller number and its still not equal to the random number and if it's equal to the random number you win.
this error appears :
fatal error: unexpectedly found nil while unwrapping an Optional value
As Tristan Beaton pointed out, readLine() doesn't work on playground hence your userInput is always nil.
CREATE A COMMAND LINE TOOL APPLICATION
CHOSE SWIFT WHEN YOU SAVE
COPY AN PASTE YOUR CODE
RUN AND PLAY
Also be really careful when you force unwrapping. That's always a crash waiting to happen ;) You can read this tutorial
I have tested this in a Command Line Tool and it worked. Also don't force unwrap optionals since you can just check if they have data without crashing the app.
I have added continue statements within your other if statements. Although it isn't really needed in this case, it is good practice to have it so that any code after the continue doesn't get executed. It just saves a bit of computing power.
import Foundation
func randomnumber(low: Int, high: Int) - >Int {
let range = high - (low-1)
return (Int(arc4random()) % range) + (low - 1)
}
let answer = randomnumber(low: 0, high: 100)
var turn = 1
while (true) {
print("Guess #\(turn): enter a number between 0 and 100")
if let userinput = readLine() {
if let guess:Int = Int(userinput) {
// Putting this here will only increase the guess count if their input in a number.
turn += 1
if guess < answer {
print("choose a higher number")
continue
}
if guess > answer {
print ("choose a smaller number")
continue
}
if guess == answer {
print("wohoo you won")
break
}
}
}
}
This is the console output

Difference between Swift shell and Swift compiled

I'm new to swift and today I wrote a small script to test it for scientific application.
Regarding the small application I wrote, it appears that it is slower than C++ but faster than python. However, I noticed that, if I run my application using the interpreter (like from terminal swift main.swift) or I compile it, there is no difference in the execution time.
Am I missing something or is it normal. I would have expected a considerable speed-up in the compiled version. Here the sample code:
import Foundation
func isPrime(num:Int) -> Int {
var IsPrime = 0
var count = 1
for index in 1...num-1 {
if (num % index != 0) {
++count
}
}
if (count == num-1) {
IsPrime = 1
}
return IsPrime
}
var isReallyPrime = 0
var maxNum = 10000
print(isPrime(21))
let methodStart = NSDate()
var primeArray = [Int]()
for index in 2...maxNum-1 {
if (index%1000 == 0) {
print("Iterarion \(index)")
}
if (isPrime(index) == 1) {
primeArray.append(index)
}
}
let methodFinish = NSDate()
let executionTime = methodFinish.timeIntervalSinceDate(methodStart)
var last = primeArray.last
print("Last prime number: \(last)")
print("Execution time [s]: \(executionTime)")
swift main.swift
compiles the Swift code and then runs it. So the only overhead compared to a compiled binary is that the code is compiled on every invocation.
You can even pass compiler options such as the optimization level:
swift -Onone main.swift
swift -O main.swift
swift -Ounchecked main.swift