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 --helpandswiftgen templates list - Make your first
swiftgen.ymland 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.pngandInputData/planets@3x.pngto 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
CFBundleNamefromInfo.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
AutoEquatabletemplate and make it work on theItemtype.
(You might want to duplicate and customize the template to remove thepublicaccess modifier) 😉 - Bonus: Use Sourcery Annotations
// sourcery:skipEqualityto exclude some fields fromAutoEquatableon models (e.g.id)
(†) Alternatively you can download the ZIP file for Sourcery and unzip it in your repo.
- Create Custom template listing all
Modeltypes. Use the--watchmode to iterate - Make the template evolve to re-generate the
enum Itembased on thoseModel-conforming types - Add the generation of the
imageanddescriptionproperties and theEncodableconformance - Add a custom annotation to identify the name property and generate the
var namefrom it - Make the
func item() -> Iteminextension ID/ID.swiftbe generated by Sourcery instead
- Make
Item+Fields.swiftbe generated by Sourcery - Use a custom annotation to exclude the
openingCrawlproperty from the fields - Make
ItemStore.swiftand itssubscriptandstatic let filtersbe generated by Sourcery
- Mark the
Planetto conform toModeland 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.swiftto generateperson.homeworld.displayName
- Rename
struct Filmtostruct Movieand 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
idoropeningCrawlto 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 thatinitcode.- Tip: when looping over all your
storedVariables, you can checkforloop.lastto see if you're on the last element of your list and omit the comma in that case.
- Tip: when looping over all your