Make your life easier with File Templates

Andrej Jasso
GoodRequest
Published in
14 min readJul 7, 2020

How to create templates for Xcode? (Documentation and repository included!)

If you are like me you love writing iOS code but there is nothing that breaks your creativity more than boilerplate code and having to think about it while some other more creative solutions might reside in your mind at the same time. Even if you have a pretty good idea about your architecture it is surely a waste of time to write boilerplate since it’s just repeating code. All you need is a bunch of good templates and writing code in any architecture should be easier for you as well and easier to get into for new members of the team. But it has a catch. Xcode templates aren’t exactly what you would call a well-documented part of the tool. That is why I decided to bring you through the process of building these from scratch to save you the trouble I went through with collecting the knowledge on this subject.

Writing templates has these advantages:

  • Makes you save time in the long run if you take time to maintain and write your templates well
  • It takes less time to onboard new people because they will not work from scratch
  • It helps maintain code conventions that you set up for yourself and your team

If you ever wanted to export your snippets you’ll notice one similarity with templates and that is that they are saved locally and outside of any project that you are working on. That means that it's a great opportunity to upload those to a repository to be able to share them or to change your workstation while keeping up to date.

The first thing you want to do is to navigate to the folder that will contain your templates. Normally you should find that in the directory /Users/$USER_NAME/Library/Developer/Xcode. You can navigate there in finder although you might have a little bit of trouble seeing the library folder as it is hidden by default. You should be able to see hidden folders by pressing the shortcut shift+cmd+. in finder. Otherwise, there are a lot of ways to permanently enable seeing hidden folders. Once you navigate here you want to create a new folder with the name Templates here and inside another folder or to be more specific because in reality there are two types of templates File templates and Project Templates. I’ll show you how to create File Templates. You can create a folder by opening the folder in a terminal window and writing the command mkdir Templates. If you do a mistake you can easily erase it by typing rm -rf NameWithTypo. For easier access, you can just drag and drop it in your favorites column on the left of the finder.

There are file templates that allow you to create files in an existing project while you choose where the file is placed in the project and there are project templates that are used to create entire projects. I’ll start talking about the file templates and then change into project templates.

File Templates

As mentioned above, first we need to create a folder for the file templates. when you are already in the previously mentioned folder /Users/$USER_NAME/Library/Developer/Xcode/Templates all you need to do it to create a folder File\ Templates. The \ sign followed by a space means that the space after the \ sign is part of the string name and not a parameter of the command. When you are done the path should look like this /Users/$USER_NAME/Library/Developer/Xcode/Templates/File Templates. Now from here where you put the Templates will have following results

  • You can put the templates anywhere from the Templates folder more in-depth and they will display in the file creation window in a section named with the parent folder
  • You can you the existing section names to put it in front with the first templates for visibility
  • You can stay organized and keep file templates in the file templates folder and even divide by project depending on if you use different architectures on different projects

Regardless of which you choose the templates will display when you attempt to create a new file in Xcode.

But how to go about creating the actual template? That’s easy, we’ll just borrow the already existing templates that Xcode provides. Open Finder and press the command cmd+shift+G and enter this address /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates

Here you can choose from a variety of templates. You can also add this to your favorite places. Let’s pick the one in Source and Cocoa Touch Class. All you need to do is copy it and place it in your folder. When you attempt to create a new file now your template should be visible in a section with the folder name.

When you enter the .xctemplate file you can see a lot of files but the necessary ones are just 4 of them.

The Template.plist file, the TemplateIcon.png TemplateIcon@2x.png and at least one template file to create, because otherwise what’s the point without. In the case of the cocoa touch class, they are in separate folders and as you can see there is a big variety.

The TemplateIcon.png TemplateIcon@2x.png files are for the icon displayed in the file creation wizard window and you can change it as long as you keep the same names.

The Template.plist file is a configuration file for your template and will let you do basic as well as more advanced stuff in your templates depending on what your needs are.

The rest are the files from which the template will generate new files. For example, in the case of the cocoa touch class, you can find them in a separate folder depending on what the user chooses in the file creation wizard.

You can start by deleting all the folders and keeping there the images and the Template.plist file. To edit the plist file you can use Xcode which I don’t like and I will show you how to do it in XML code but for that, you need a good editor for the code. I recommend using Atom. It’s very easy super customizable.

After you open the Template.plist file you should see a bunch of keys but for now, just replace it with this plist that I created.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Kind</key>
<string>Xcode.IDEKit.TextSubstitutionFileTemplateKind</string>
<key>Platforms</key>
<array>
</array>
</dict>
</plist></plist>

The Kind key makes xcode able to tell if the template is File template or a project template since they both use the same file extension.

The Platforms key specifies on which platform can the template be used. You can make templates for macOS or iOS etc.

The next key is important: Options. The options define what you show in the file creation wizard.

If you leave your key options empty you create a template without any additional settings possible, just the files you define in the root space of the template and nothing more. Those files you can modify but its always going to be those files. To be honest, it is enough if you want to do a simple template.

Let's create some files in the template.

There are several different pre-defined constants you can use including:

  • ___COPYRIGHT___ – the copyright message.
  • ___DATE___ — the current date when the new project is created.
  • ___DIRECTORY___ — the full path of directory in which the new file is being created.
  • ___FILEBASENAME___ — the current file name without extension.
  • ___FILEBASENAMEASIDENTIFIER___ — same as FILEBASENAME, but modified to be a legal C-style identifier.
  • ___FILEEXTENSION___ — the extension of the file.
  • ___FILENAME___ — the file name (with extension) as typed by the user.
  • ___FULLUSERNAME___ — the full name of the current Xcode user.
  • ___ORGANIZATIONNAME___ — the organization name as specified in the New Project wizard.
  • ___PACKAGENAME___ — package name entered by the user in the New Project wizard.
  • ___PARENTPACKAGENAME___ –
  • ___PROJECTNAME___ — the name of the project in which file is created, empty if no project.
  • ___PROJECTNAMEASIDENTIFIER___ — same as PROJECTNAME, but modified to be a legal C-style identifier.
  • ___TIME___ – the current time when the file is created.
  • ___USERNAME___ – the account name of the logged-in user.

Along with these, there are others I've seen prefixed with IMPORTHEADER but I haven't figured out where they come from yet.

  • ___IMPORTHEADER_categoryClass___
  • ___IMPORTHEADER_extensionClass___
  • ___IMPORTHEADER_cocoaTouchSubclass___

Constants can also be created via Macros and from the New Project Wizard Options. I will not go into macros since I don’t use them myself, you can find a guide about them in the link in the sources. I’ll show you how to use File Wizard Options constants.

This last group of variables is also directly related to the New File Wizard and they're the variables that represent the chosen options. For example, if the template asks the user for a class name, the option might use userSubclass as the option name, in which case the template would also include a constant with that variable's value. These constants follow the same format but are also prefixed with VARIABLE like this:

___VARIABLE_userSubclass___

Common examples in Apple's templates include:

  • ___VARIABLE_classPrefix:identifier___
  • ___VARIABLE_categoryClass:identifier___
  • ___VARIABLE_extensionClass:identifier___
  • ___VARIABLE_extensionName:identifier___
  • ___VARIABLE_cocoaTouchSubclass___

Keeping this in mind lets create the first generated template file. Create a new swift file and call it ___FILEBASENAMEASIDENTIFIER___ViewController.swift

The content follows this basic structure but you can change most of it to better suit your need. I was trying to create a view controller for using the MVVM architecture.

//___FILEHEADER___import UIKit// MARK: - Classfinal class  ___FILEBASENAMEASIDENTIFIER___: UIViewController {// MARK: - Outlets// MARK: - Variablesprivate var viewModel:  <#NameViewModelProtocol#>// MARK: - Lifecycleoverride func viewDidLoad() {super.viewDidLoad()viewModel.delegate = self}}extension  ___FILEBASENAMEASIDENTIFIER___:  <#NameViewModelDelegate#> {}

Now if you create a new file from this template you will specify your ___FILEBASENAMEASIDENTIFIER___ in the wizard along with the folder where you want to place it and as soon as you check OK they files start to generate in the chosen folder. Simple right?

A little improvement

You might have noticed that the template is not perfect though since the file name ends with the string ViewController and every time you refer to ___FILEBASENAMEASIDENTIFIER___ in the swift file the entire name with ViewController included is called. Like this, you can’t use only the root of the word and refer to the view-model with the same root name from the view controller.

To resolve this little issue you need to create a Project Wizard Constant. For that, we’ll need to modify the Template plist file a little bit. We add an option in the options array.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Kind</key>
<string>Xcode.IDEKit.TextSubstitutionFileTemplateKind</string>
<key>Platforms</key>
<array>
<string>com.apple.platform.iphoneos</string>
</array>
<key>Options</key>
<array>
<dict>
<key>Identifier</key>
<string>ID</string>
<key>Required</key>
<true/>
<key>Name</key>
<string>Base Name</string>
<key>Description</key>
<string>The name of the Model, View and ViewModel to create</string>
<key>Type</key>
<string>text</string>
<key>Default</key>
<string>MyModel</string>
<key>NotPersisted</key>
<true/>
</dict>
<dict/>
</array>
</dict>
</plist>

The new options have the Identifier set to RootNameso to access it in the fileName and inside the file, you call ___VARIABLE_RootName___

The Required field you should add in every field that is required which is self-explanatory.

The Name field value is displayed next to the field in the wizard

The Description value is displayed in a tooltip box when you have on the option in the wizard

The Type key defines what type of option we are dealing with. They can be text, popup, checkbox

The Default value defines the default value of the option

The NotPersisted value defines if the chosen option will be remembered (or persisted) until the next time you use the template.

In this way, you can access the root name event in the controller and still refer to the view model like this.

//___FILEHEADER___import UIKit// MARK: — Classfinal class ___VARIABLE_ID___ViewController: UIViewController {// MARK: — Outlets// MARK: — Variablesinternal var viewModel: ___VARIABLE_ID___ViewModelProtocol// MARK: — Lifecycleoverride func viewDidLoad() {super.viewDidLoad()viewModel.delegate = self}}extension ___VARIABLE_ID___ViewController: ___VARIABLE_ID___ViewModelDelegate {}

You can also add a matching view model

//___FILEHEADER___// MARK: — View Model Delegateprotocol ___VARIABLE_ID___ViewModelDelegate: AnyObject {}// MARK: — View Model Protocolprotocol ___VARIABLE_ID___ViewModelProtocol: AnyObject {var delegate: ___FILEBASENAMEASIDENTIFIER___Delegate? { get set }}// MARK: — View Model Protocol Implementationfinal class ___VARIABLE_ID___ViewModel: ___VARIABLE_ID___ViewModelProtocol// MARK: — Structstruct State {}// MARK: — Delegateweak var delegate: ___VARIABLE_ID___ViewModelDelegate?// MARK: — Variableprivate var state: Stateprivate var di: Dependency// MARK: — Initializerinit(dependencyInjection: Dependency, configuration: Config) {self.di = dependencyInjection}}

This being done you can also use the variable in the filename instead of the ___FILEBASENAMEASIDENTIFIER___

Now all we need to do is to add also a story board. We can help ourselves and take the template from the existing templates to create our storyboard.

Its located in the User interface folder of the default template. And remove the launchScreen = “YES” option

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
</scenes>
</document>

The template however creates only an empty storyboard. But what if we want to already have a ViewController in place. The Launch Screen template provides such storyboard file.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="___COPYRIGHT___" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="0.0" y="626.5" width="375" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="___PACKAGENAME___" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

In this case, all we need to do is to connect the storyboard to the view controller. Well all we need to do is add it in the file after its generated and see what changed compared with this file

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" customClass="___VARIABLE_ID___ViewController" customModuleProvider="target" sceneMemberID="viewController">>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="___COPYRIGHT___" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="0.0" y="626.5" width="375" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="___PACKAGENAME___" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

What we modified was the first header line of the source code header for the view controller like this

<viewController id=”01J-lp-oVM” customClass=”___VARIABLE_RootName___ViewController” customModuleProvider=”target” sceneMemberID=”viewController”>>

After this the UIViewController should be connected to the Storyboard UIViewController right after generation. Your template should look like this inside:

As you can notice I am using the _VARIABLE_RootName___ also for the file names so anything I write in the ___FILEBASENAMEASIDENTIFIER___ gets ignored.

Advanced templates

If you want to have a more advanced template like the cocoa touch template for example you need to add more options. There are two main ways you want to do. A checkbox, or a popup. A checkbox has an ID and two values and a popup can have multiple values that you define a fork your folder structure in this way. So for example, if you have a popup with values ViewController and TableViewController and a checkbox with an ID Coordinator and you need to have your folders in the template structured like this:

Each folder contains all of the files connected with the template. You can choose just some files with certain values but this is possible in project templates and not in file templates. So basically if you look at the cocoa touch file template, that is as complex of a file template as it gets. The Template.plist for the above option would be this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Kind</key>
<string>Xcode.IDEKit.TextSubstitutionFileTemplateKind</string>
<key>Platforms</key>
<array>
<string>com.apple.platform.iphoneos</string>
</array>
<key>Options</key>
<array>
<dict>
<key>Identifier</key>
<string>ID</string>
<key>Required</key>
<true/>
<key>Name</key>
<string>Base Name</string>
<key>Description</key>
<string>The name of the Model, View and ViewModel to create</string>
<key>Type</key>
<string>text</string>
<key>Default</key>
<string>MyModel</string>
<key>NotPersisted</key>
<true/>
<key>Nodes</key>
<array>
<string>Base</string>
</array>
</dict>
<dict>
<key>Identifier</key>
<string>TemplateType</string>
<key>Required</key>
<string>YES</string>
<key>Name</key>
<string>Type</string>
<key>Description</key>
<string>What type of template</string>
<key>Type</key>
<string>popup</string>
<key>Default</key>
<string>ViewController</string>
<key>Values</key>
<array>
<string>ViewController</string>
<string>TableViewController</string>
</array>
</dict>
<dict>
<key>Identifier</key>
<string>Coordinator</string>
<key>Name</key>
<string>Include coordinator</string>
<key>Description</key>
<string>Include coordinator in the template</string>
<key>Type</key>
<string>checkbox</string>
<key>RequiredOptions</key>
<dict>
<key>TemplateType</key>
<array>
<string>ViewController</string>
<string>TableViewController</string>
</array>
</dict>
<key>Default</key>
<string>false</string>
<key>NotPersisted</key>
<true/>
</dict>
<dict/>
</array>
</dict>
</plist>

Each file in each folder has to be modified to fit your needs as well. So for example for the tableView folder, you would create an empty launchScreen place a tableview with constraints and add the changes to the storyboard file.

The new values found in this plist are:

The RequiredOptions which specifies the prerequisites for this option to be enabled otherwise it’s greyed out

The Values key specifies which values are going to be shown in a popup.

Congratulations. After this tutorial, you should be able to create templates for a chosen architecture for example MVVM or Redux. Your imagination is the only limit 🙂

Work in progress:

https://github.com/meteora8888/swiftTemplates

Here’s my report where I keep the templates. I have them linked to the Templates folder directly.

Sources:

https://github.com/NSBoilerplate/Xcode-Project-Templates/wiki/Creating-Xcode-4.x-Project-Templates

https://medium.com/@popcornomnom/swift-tutorial-how-to-create-own-xcode-file-template-for-ios-and-macos-d2e535ed62c5

--

--