To add an executable target to our package, we will edit the Package.swift file to add a new short section under targets (the new target definition in bold):
.target(
name: "swURL",
dependencies: []),
.target(
name: "swURLCli",
dependencies: ["swURL"]),
.testTarget(
name: "swURLTests",
dependencies: ["swURL"]),
Then, we create a new swURLCli directory under the Sources directory to contain the new swURLCli executable source files. Finally, add a main.swift file in swURLCli with the following content:
import Foundation
import swURL
struct Todo: Decodable {
let userId: Int
let id: Int
let title: String
let completed: Bool
}
func doTask(completion: @escaping (_ data: Todo?, _ error: Error?) -> Void) {
let group = DispatchGroup()
group.enter()
swURL.get(url: URL(string: "https://jsonplaceholder.typicode.com/todos/1")!,
completion: { (result : Todo?, error: Error?) in
completion(result, error)
group.leave()
})
group.wait()
}
doTask { (result : Todo?, error: Error?) -> Void in
print("Hello, world!")
}
As you can see, we made sure to synchronize our main thread with the asynchronous network operation using a dispatch group. Had we not done this, the main thread would exit before the asynchronous task had a chance to finish. To double-check that everything is fine, this is how your directory hierarchy should look:
$ tree
.
├── Package.swift
├── README.md
├── Sources
│ └── swURL
│ └─── swURL.swift
│ └── swURLCli // new directory
│ └──── main.swift // new file
└── Tests
├── LinuxMain.swift
└── swURLTests
├── XCTestManifests.swift
└── swURLTests.swift
Now you can run swift build, which should output the following information:
$ swift build
Compile Swift Module 'swURLCli' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/swURLCli
The ./.build/x86_64-apple-macosx10.10/debug/swURLCli file is your new executable, which you can run from the command line. Now that we have an executable, let's link it to an external library to understand how dependency management works in SPM.