Sharing Swift Code Between iOS and Server Applications

In this tutorial, you’ll learn how share code between iOS and server applications. By Christian Weinberger.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Migrating AcronymAPIModel

Now, you’re migrating the last API model, AcronymAPIModel:

  • First, copy and paste the contents of Vapor’s AcronymAPIModel.swift into your AcronymAPIModel.swift file in the TILCore library project.
  • Replace import Vapor with import Foundation.
  • Next, replace the conformance to Content with Codable.
  • Remove the convenience initializer init(acronym:) that’s only needed by Vapor and requires an Acronym entity.
  • Finally, delete makeAcronym() within AcronymAPIModel.Create.

The AcronymAPIModel.swift in TILCore will look like this now:

import Foundation

public struct AcronymAPIModel: Codable {
  public let id: UUID
  public let short: String
  public let long: String
  public let user: UserAPIModel
  public let categories: [CategoryAPIModel]

  public init(
    id: UUID,
    short: String,
    long: String,
    user: UserAPIModel,
    categories: [CategoryAPIModel]
  ) {
    self.id = id
    self.short = short
    self.long = long
    self.user = user
    self.categories = categories
  }
}

extension AcronymAPIModel {
  public struct Create: Codable {
    public let short: String
    public let long: String
    public let userID: UUID

    public init(short: String, long: String, userID: UUID) {
      self.short = short
      self.long = long
      self.userID = userID
    }
  }
}

Build the TILCore project. It should succeed without errors.

Integrating With Your Vapor App

Now that your TILCore project is up and running, it’s time to integrate!

Setting Up a Local Git Repository for Your Library

At the time of writing, Xcode does not support having two projects open that depend on a local Swift package — specified using a path — at the same time. To work around this limitation, create a local git repository for your TILCore project and add it as a git dependency to your iOS and Vapor apps instead.

In Terminal, switch to your til-core directory within the starter package and run these commands:

#1
git init
#2
git add .
git commit -m "Initial commit"
git branch -M main
#3
pwd

This is what it does:

  1. Initializes a new git repository for your til-core directory.
  2. Adds all changed files to the Git index and commits them into your local repository. It then changes the branch to main.
  3. Prints out the full path of the directory, in this case it’s /Users/cweinberger/dev/cweinberger/rw-code-sharing-ios-vapor/til-core.
Note: Since you’re integrating the library as a git dependency, you have to git add and git commit any updates you do to TILCore before they’re visible in your Vapor and iOS app.

Adding the Library to Your Vapor App

Head over to your Vapor project and open Package.swift. Currently, there are three dependencies: Vapor, Fluent and Fluent PostgreSQL Driver. Add a new one below .package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0"),:

.package(url: "file:///Users/cweinberger/dev/cweinberger/rw-code-sharing-ios-vapor/til-core", .branch("main"))

This adds the dependency from the local TILCore git repository. The URL is the printed output of pwd that you ran, recently prefixed with file://.

Next, add TILCore as a dependency to your App target. Below .product(name: "Vapor", package: "vapor"), add:

.product(name: "TILCore", package: "til-core")

If Xcode doesn’t update the dependencies, you can trigger this manually. In the Xcode menu bar, select File ▸ Swift Packages ▸ Update to Latest Package Versions.

Configuring the API Models

To use the API models in Vapor, they must conform to Vapor-specific protocols. You also want to keep the Vapor-specific implementation you removed from the shared package.

In your Vapor project, create a new folder, APIModels+Vapor, under Sources/App/Models and add three new Swift files: AcronymAPIModel+Acronym.swift, CategoryAPIModel+Acronym.swift and UserAPIModel+Acronym.swift.

Open AcronymAPIModel+Acronym.swift and insert the following:

// #1
import TILCore
import Vapor

// #2
extension AcronymAPIModel: Content {}

// #3
extension AcronymAPIModel {
  init(_ acronym: Acronym) throws {
    try self.init(
      id: acronym.requireID(),
      short: acronym.short,
      long: acronym.long,
      user: UserAPIModel(user: acronym.user),
      categories: acronym.categories.map { try CategoryAPIModel(category: $0) }
    )
  }
}

// #4
extension AcronymAPIModel.Create {
  func makeAcronym() -> Acronym {
    Acronym(short: short, long: long, userID: userID)
  }
}

Here’s what the code does:

  1. Imports TILCore to have access to the shared models and Vapor to add Vapor-specific implementation.
  2. Conforms to Vapor’s Content protocol.
  3. Brings back the initializer that initializes AcronymAPIModel from Acronym.
  4. Brings back the convenience method that creates Acronym from AcronymAPIModel.Create.

Now, repeat the steps for the other API models.

Open CategoryAPIModel+Category.swift and insert:

import TILCore
import Vapor

extension CategoryAPIModel: Content {}

extension CategoryAPIModel {
  init(category: Category) throws {
    try self.init(
      id: category.requireID(),
      name: category.name
    )
  }
}

extension CategoryAPIModel.Create {
  func makeCategory() -> Category {
    Category(name: name)
  }
}

Open UserAPIModel+User.swift and insert:

import TILCore
import Vapor

extension UserAPIModel: Content {}

extension UserAPIModel {
  init(user: User) throws {
    try self.init(
      id: user.requireID(),
      name: user.name,
      username: user.username
    )
  }
}

extension UserAPIModel.Create {
  func makeUser() -> User {
    User(name: name, username: username)
  }
}

Next, remove the APIModels folder in your Vapor project by right-clicking the folder and selecting Delete.

Build the Vapor project now and you’ll find a lot of errors similar to:
/Sources/App/Controllers/AcronymsController.swift:45:65: Cannot find type ‘AcronymAPIModel’ in scope.

Puppy monster with surprised face

Your API models are no longer part of the Vapor project, they are part of the TILCore package. You have to import TILCore anywhere you use these models.

Add import TILCore to the three controllers: AcronymsController.swift, CategoriesController.swift and UserController.swift.

Build and run the project and notice that all errors are gone.

Puppy monster with happy face

Great! Your Vapor project now uses the API models from your TILCore library! It also extends them with the required Vapor-specific functionalities. :]

Integrating With Your iOS App

Now you’ve integrated TILCore with your Vapor app, it’s time to do the same with your iOS app!

Adding the Library to Your iOS App

Head back to your iOS app project and select the project file. In the main window, select Project ▸ TILiOS, navigate to the Swift Packages tab and click the + button.

Enter the same repository URL that you’ve used for the Vapor app: file:///Users/cweinberger/dev/cweinberger/rw-code-sharing-ios-vapor/til-core, in this case.

Click Next and make sure that you select the Branch radio button under Rules. The main branch should show up. Select Next and double-check that TILiOS is selected as the target. Complete the process by clicking Finish.

Add TILCore package to the iOS project

You’ll see the til-core package in your Swift Package Dependencies now.

Using the Shared API Models

Next, delete the Models folder in your iOS project, as you want to use the ones from the TILCore package. Build the project and you’ll see a lot of errors similar to the ones you got on the Vapor project earlier: TILiOS/ViewControllers/CreateUserTableViewController.swift:65:16: Cannot find ‘UserAPIModel’ in scope.

Add import TILCore to all the ViewControllers and to TILAPI.swift.

Build and run the Vapor project, then build and run the iOS app.

Great! Your iOS app works as expected and shares the API models with your Vapor app. :]

Swift mascot badge