Swift 4 Cookbook – Linux & MacOS, part 1
Swift is powerful, fast and safe programming language. From version 2 it’s open source, and officialy supported on Linux. Its native performance, type safety, interactive (REPL) playground and scripting posibility, is a joy to use.
The main goal for Swift on Linux is to be compatible with Swift on macOS/ios/watchos, and there is an official Apple documentation for Foundation. Howerever, this quick cheat-sheet gives you quick glance what this language+standard library is capable of.
Setup
There are 2 ways to install Swift 4 for server side applications:
- Standard installation:
Download Swift 4.0 from: swift.org for your Ubuntu distribution, following manual
- You can also use Docker instead, (it runs on all distros)
docker run --rm --privileged -ti swiftdocker/swift:latest /usr/bin/swift -I /usr/lib/swift/clang/include/
What’s so special about Swift 4 ?
- expressive, high level language with generics
- safe by design(type safety, optionals, error handling, undefined behavior detection)
- native code compilation with high runtime performance
- seamless, zero cost C language interoperability without hacks
- efficient memory management arc and ownership
- functional paradigms included
How to use this tutorial
- Make sure you read this great intro to Swift 4
- This tutorial is about using Foundation API’s, it’s not a language guide.
- This tutorial doesn’t cover writing web app in swift, though – it’s coming soon!
To play with examples in this tutorial, you can use swift REPL. You also compile the code with swiftc [file.swift]
- To run REPL:
- On Mac – just type
swift
- Linux – type:
swift -I /usr/lib/swift/clang/include/
- On Mac – just type
- You can also use XCode playground – fire up Xcode, then
File -> New -> Playground
More capabilities of Swift REPL here
Printing text
>print("Hello world!")
Hello world
>print("""
Hello\nworld!
""")
Hello
world
>print("one", "two", "three")
one two three
>print("one", "two", "three", separator: ",")
one,two,three
>print("one", "two", "three", separator: "\n")
one
two
three
>print(1, "and", 2)
1 and 2
Printing to stderr
import Foundation
FileHandle.standardError.write("test".data(using: .utf8)!)
Printing to stdin
import Foundation
FileHandle.standardError.write("test".data(using: .utf8)!)
FileHandle.standardInput.write("test".data(using: .utf8)!)
FileHandle.standardOutput.write("test".data(using: .utf8)!)
Executing shell commands
Run process with arguments and wait for completion
import Foundation
let p = Process()
p.launchPath = "/usr/bin/wc"
p.arguments = ["-l", "/etc/passwd"]
p.launch()
p.waitUntilExit()
Suspend and resume process in background
import Foundation
let p = Process()
p.launchPath = "/bin/cat"
p.arguments = ["/var/log/system.log"]
p.launch()
p.suspend()
sleep(1)
p.resume()
sleep(1)
p.terminate()
Monitor process running in background
This example prints system logs for 10 seconds, and then exits.
import Foundation
let p = Process()
p.launchPath = "/usr/bin/tail"
p.arguments = ["-f", "/var/log/system.log"]
p.launch()
var elapsedSeconds = 10
while p.isRunning && elapsedSeconds > 0 {
print("Running")
sleep(1)
elapsedSeconds -= 1
}
Redirect stdin / stdout
import Foundation
let p = Process()
p.launchPath = "/bin/cat"
p.arguments = ["-"]
let pp = Pipe()
p.standardInput = pp
p.launch()
pp.fileHandleForWriting.write("test\n\u{4}".data(using: .utf8)!)
p.waitUntilExit()
Networking
Download HTTP document
import Foundation
let downloadURL = URL(string: "http://www.google.com")!
let contents = String(contentsOf: downloadURL, encoding: .utf8)
print(contents)
Download HTTP document and autodetect(sniff) encoding
import Foundation
var x: String.Encoding = String.Encoding.ascii
let url = "https://www.ecma-inational.org/publications/files/ECMA-ST/Ecma-128.pdf"
try? String(contentsOf: URL(
string: url)!,
usedEncoding: &x)
print(x)
Download binary file
import Foundation
let fileContents = Data(contentsOf: URL("http://filea.x")!)
Note: It uses RAM memory to store entire file in it, it can be handy for smaller files / quick scripts.
Download in parts(chunks)
import Foundation
import Dispatch
let config = URLSessionConfiguration.default
let s = URLSession(configuration: config)
let task = s.downloadTask(with: URL(string: "http://google.com")!) { url, response, err in
count += 1
print(count)
}
task.resume()
Filesystem operations
Read binary file
import Foundation
let binaryData = Data(contentsOf: URL(fileURLWithPath: "/tmp/a.x"))
Read text file
import Foundation
let textFile = String(contentsOf: URL(fileURLWithPath: "/etc/passwd"))
Write to text file
import Foundation
"hello world".write(toFile: "/etc/xxx", atomically: true, encoding: .utf8)
Write to stderr
import Foundation
FileHandle.standardError.write("test".data(using: .utf8)!)
Write to stdin
import Foundation
FileHandle.standardError.write("test".data(using: .utf8)!)
FileHandle.standardInput.write("test".data(using: .utf8)!)
FileHandle.standardOutput.write("test".data(using: .utf8)!)
Read data in chunks
import Foundation
let f = FileHandle(forReadingAtPath: "/etc/passwd")
f!.readData(ofLength: 10)
// all:
f!.readDataToEndOfFile()
Check if file is readable
import Foundation
if FileManager.default.isReadableFile(atPath: "/etc/fstab") {
}
Remove file
import Foundation
FileManager.default.removeItem(at: URL(fileURLWithPath: "/tmp/x")!)
Copy file
import Foundation
FileManager.default.copyItem(atPath: "from.txt", toPath: "to.txt")
Copy directory
import Foundation
FileManager.default.copyItem(atPath: "/etc/", toPath: "/etc.backup")
List directories
import Foundation
// Shallow list without folders
for entry in FileManager.default.contentsOfDirectory(atPath: "/") {
}
// deep list
for item in FileManager.default.enumerator(atPath: "/etc")! {
print(item)
}
Recursively list files
import Foundation
FileManager.default.subpathsOfDirectory(atPath: "/root/")
Create directory with permissions
import Foundation
let permission = 0o700 as NSNumber
FileManager.default.createDirectory(
atPath: "/tmp/my/brand/new/directory",
withIntermediateDirectories: true,
attributes: [.posixPermissions: permission]
)
Coroutines / threads /
Swift comes with LibDispatch which uses threads and queues for dealing with asynchronous tasks.
Concurrent requests example
import Foundation
import Dispatch
let config = URLSessionConfiguration.default
let s = URLSession(configuration: config)
var count = 0
for i in 1...100 {
let task = s.downloadTask(with: URL(string: "http://www.wp.pl")!) { url, response, err in
count += 1
print(count)
}
task.resume()
print("Started")
}
dispatchMain()
Scripting with Swift
You can use Swift as a interpreted language, too with pure text files!
Just create swift file:
touch /tmp/hello && chmod a+x /tmp/hello
With contents:
#!/usr/bin/xcrun swift
import Foundation
print("Hello, what's your name?")
let name = readLine(strippingNewline: true)
print("Hello, \(name)")
Run it with /tmp/hello
Voila! You can execute any of examples using this technique.