Learn to use SwiftGen & Sourcery to avoid boilerplate and improve your productivity. CodeGen also allows you to provide more type safety & make your code maintenance!
- This workshop expects that you already know how to write Swift 4+ code and have written a few (ideally iOS) applications.
- We'll use Xcode 10.2, but older Xcodes should work too
During the workshop, we'll use the following websites
- SwiftGen & Sourcery repositories for their README & documentation
- Sourcery dedicated documentation's website
- Stencil documentation
- StencilSwiftKit for additional Stencil tags and filters documentation
Note: This project is in no way intended to be a model of good architecture 😅 It has been crafted specifically to feature as many possible use cases for Code Generation as possible while trying to keep the app as simple as possible. 😉
- Browse the source code quickly
- Compile and launch the project in Xcode – ow, it crashes, what a good start!
- Identify the issues with hardcoded values and crashes:
- Localization: wrong keys, untranslated 🚫
- Images: wrong keys, crash 💥
- Fonts: wrong name, some missing in Info.plist, fallback to system font 🚫
- Storyboards: hardcoded Storyboard and Scene names, crash 💥
- Models: Lots to data to type by hand ⌨️
- Info.plist : hardcoded keys 🚫
- Lottie: hardcoded name, one animation not found 🚫
- Identify the annoying repetition of code
- Big switches just to identify a name property
- Image associated with Item should be derived from item case
- Equatable implementations for enums
- ...
- Install SwiftGen via CocoaPods (†)
- Read the doc about the Config File format, play with
swiftgen --help
andswiftgen templates list
- Make your first
swiftgen.yml
and generate constants for xcassets via the command line - Fix the code that is using images and colors
- Add the generated file to your project
- Start using the generated constants in the code, see that some are missing
- Install SwiftGen as a Build Phase in your project so that you get constant updates
- Add
InputData/person@3x.png
andInputData/planets@3x.png
to your Assets Catalog and rebuild to see new constants.
- Add
- Continue with all the other types of resources
- Fonts to
swiftgen.yml
– Don't forget to remove them from the Info.plist too! - Storyboards and Scene names
NSLocalizedString
- Hardcoded
CFBundleName
fromInfo.plist
- Fonts to
- Bonus: Play a bit by renaming your image assets or Storyboard IDs and see how the changes are now warning you at compile time about where to change their references
(†) Alternatively you can download the ZIP file for SwiftGen and unzip it in your repo.
- Discover Stencil doc
- Create a Lottie template to list all animations, add generated code to Xcode, replace call sites to fix the wrong animation name. In addition to generate the name of JSON files, also try to extract the width and height of the animations from the JSON content.
- Create templates for YAML model files (see
InputData/
), in order to generate all the model objects (replacing the content of files inGenerated/
- Install Sourcery via CocoaPods (†)
- Install it as a Build Phase in your project
- Take a look at its README and online documentation
- Use the
AutoEquatable
template and make it work on theItem
type.
(You might want to duplicate and customize the template to remove thepublic
access modifier) 😉 - Bonus: Use Sourcery Annotations
// sourcery:skipEquality
to exclude some fields fromAutoEquatable
on models (e.g.id
)
(†) Alternatively you can download the ZIP file for Sourcery and unzip it in your repo.
- Create Custom template listing all
Model
types. Use the--watch
mode to iterate - Make the template evolve to re-generate the
enum Item
based on thoseModel
-conforming types - Add the generation of the
image
anddescription
properties and theEncodable
conformance - Add a custom annotation to identify the name property and generate the
var name
from it - Make the
func item() -> Item
inextension ID
/ID.swift
be generated by Sourcery instead
- Make
Item+Fields.swift
be generated by Sourcery - Use a custom annotation to exclude the
openingCrawl
property from the fields - Make
ItemStore.swift
and itssubscript
andstatic let filters
be generated by Sourcery
- Mark the
Planet
to conform toModel
and changePerson.homeworld: ID<Planet>
andFilm.planets: [ID<Planet>]
- Check that rebuilding – and thus re-running Sourcery – should now update all the places where we depend on Item cases (
ItemStore.generated.swift
,Item+Fields.generated.swift
,Item.generated.swift
) - Change your template for
Item+Fields.generated.swift
to generateperson.homeworld.displayName
- Rename
struct Film
tostruct Movie
and everyID<Film>
intoID<Movie>
, then ensure everything changes automatically in the rest of the code too.
Notice that the compiler will prompt us to rename the corresponding image too. Rename it and see SwiftGen re-generate the proper constants - Custom Encodable for Models, mark some properties like
id
oropeningCrawl
to be ignored
- Change your model types to be classes.
- Since classes require an explicit
init
, you'll have to generate one... and it has to be declared in the original type implementation (you can't declare it in anextension
). So we're gonna need to make Sourcery generate code inline, inside our existing code - Look at the Sourcery documentation about Writing Templates – see how to achieve that with special
// sourcery:inline:...
annotations, and make a template to generate thatinit
code.- Tip: when looping over all your
storedVariables
, you can checkforloop.last
to see if you're on the last element of your list and omit the comma in that case.
- Tip: when looping over all your