Adding more targets

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.

As soon as you add an executable target to your SPM package, it will stop generating a framework that you can use in iOS applications. This is because you cannot include executables in iOS apps, so Xcode will complain about the lack of a binary targeting the ARM platform within your SPM package.