Skip to content
This repository has been archived by the owner on Sep 6, 2018. It is now read-only.

SwiftGen 5.0 Migration: compatibility template

David Jennes edited this page Aug 7, 2017 · 5 revisions

Tip to migrate your code to SwiftGen 5.0's new swift3 storyboard template

Introduction

If you have been using the -t swift3 template for your storyboards with SwiftGen 4.x, your call site to use them probably looks something like this:

StoryboardScene.Photos.initialViewController()
StoryboardScene.Photos.instantiateEditVC()

With SwiftGen 5.0, that swift3 template for storyboards has improved to be swiftier and use generics to be even more type-safe. But this also means that your call site will have to change to something like this now:

StoryboardScene.Photos.initialScene.instantiate()
StoryboardScene.Photos.editVC.instantiate()

To help you transition, you can imagine use the compatibility template below — together with SwiftGen 5.0's new swift3 template — to generate some compatibility functions with deprecation warnings. This template re-generates the old functions calling the new API, but marked with the @available(*, deprecated, renamed: …) annotations, allowing you to use Xcode's Fix-It feature to let Xcode do the heavy lifting and apply the renaming for you.

⚠️ Note: this compatibility template is provided here as a tip and convenience; it is not intended to be used as a long-term template — but only during your small refactoring to migrate to SwiftGen 5.0.
This template won't be bundled in SwiftGen 5.0 (as it's only a tip to use during migration) and won't be maintained. It's only provided as a courtesy, but isn't unit-tested and won't have long-term support.

The template

To use this, copy this template into some swift3-compat.stencil file:

// Generated using SwiftGen, by O.Halligon — https://github.com/SwiftGen/SwiftGen
{% if platform and storyboards %}
{% set isAppKit %}{% if platform == "macOS" %}true{% endif %}{% endset %}
{% set prefix %}{% if isAppKit %}NS{% else %}UI{% endif %}{% endset %}
{% set controller %}{% if isAppKit %}Controller{% else %}ViewController{% endif %}{% endset %}

import Foundation
import {% if isAppKit %}Cocoa{% else %}UIKit{% endif %}
{% for module in modules where module != env.PRODUCT_MODULE_NAME and module != param.module %}
import {{module}}
{% endfor %}

{% set sceneEnumName %}{{param.sceneEnumName|default:"StoryboardScene"}}{% endset %}
{% macro className scene %}{% filter removeNewlines %}
  {% if scene.customClass %}
    {% if scene.customModule %}{{scene.customModule}}.{% endif %}
    {{scene.customClass}}
  {% else %}
    {{prefix}}{{scene.baseType}}
  {% endif %}
{% endfilter %}{% endmacro %}

{% for storyboard in storyboards %}
{% set storyboardName %}{{storyboard.name|swiftIdentifier|escapeReservedKeywords}}{% endset %}
extension {{sceneEnumName}}.{{storyboardName}} {
  {% if storyboard.initialScene %}
  {% set sceneClass %}{% call className storyboard.initialScene %}{% endset %}
  @available(*, deprecated, renamed: "initialScene.instantiate()")
  static func initialViewController() -> {{sceneClass}} {
    return initialScene.instantiate()
  }
  {% endif %}

  {% for scene in storyboard.scenes %}
  {% set sceneID %}{{scene.identifier|swiftIdentifier|snakeToCamelCase|lowerFirstWord|escapeReservedKeywords}}{% endset %}
  {% set sceneClass %}{% call className scene %}{% endset %}
  @available(*, deprecated, renamed: "{{sceneID}}.instantiate()")
  static func instantiate{{sceneID|titlecase}}() -> {{sceneClass}} {
    return {{sceneID}}.instantiate()
  }
  {% endfor %}
}
{% endfor %}

{% elif storyboards %}
// Mixed AppKit and UIKit storyboard files found, please invoke swiftgen with these separately
{% else %}
// No storyboard found
{% endif %}

Then:

  • in a terminal, just ask SwiftGen to generate the compatibility code using this template (e.g. swiftgen storyboards -p swift3-compat.stencil -o storyboards-compat.swift ./Source)
  • integrate the generated file in your project during the migration (in addition to the file generated by swiftgen storyboards -t swift3 … that you probably have in your Build Phase)
  • 💡 You can then use Xcode's Fix-It feature (and the "Editor" > "Fix All in Scope" menu item) to let Xcode do the renaming for you.
  • once the migration of your existing code is done, you can just delete the generated compatibility file and start using the new API.