How to beat a routine, or Ready-made application in Xcode in a couple of clicks



    Each experienced developer has a set of tools that he is used to and with which it is convenient for him to work. This may be the simplest environment setting, utilities for intermediate operations (for example, Postman API testing assistant), time-tested and personally developed by the library developer and snippets.

    Also, many developers may have their own approach to the implementation of the selected architecture. Therefore, it is very useful to have an application blank in your arsenal - a common skeleton, to which you only need to add new modules, screens and features. In this article I will tell you how to create your own application template in Xcode.

    Where is the heart of the template


    How often do you create applications and write the same code again and again, creating the base for the future product? You declare base classes, make helpers, lay the architecture, create wrappers ... At such moments, you want to have a tool that will instantly get a working application with a well-developed architecture and a written base for further development.

    Such a tool exists, and we all use it all the time when we create the 'Single View App' in Xcode.

    My searches for instructions from Apple to create their own templates have failed. However, in Xcode, you can add the generation of your own files with already prepared code, and this is not difficult.

    For an easy start, let's take the well-known Single View App. Go to Finder, press the key combination Cmd + Shift + G (go to the folder) and specify the path:

    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application

    Find “Single View App.xctemplate” there and copy, for example, to the desktop.
    As you can see, the template consists of only 4 files:

    • Main.storyboard. A storyboard containing the main view controller.
    • TemplateIcon.png. Icon with a resolution of 48x48.
    • TemplateIcon@2x.png. Icon with a resolution of 96x96.
    • TemplateInfo.plist. Configuration file for the template.

    Only the last file, TemplateInfo.plist, plays a significant role here, because it contains all the settings. Main.storyboard is just one of the possible files that will be added to each application created using this template. In the absence of the second and third files from this list, your template will have a default icon. Therefore, the heart of the template is TemplateInfo.plist.

    Basic properties of the configuration file


    Conventionally, the TemplateInfo properties can be divided into several categories:

    1. Template markup
    Assigning a unique identifier and additional fields to the template for display in the Xcode environment.

    Mandatory fields:

    - Identifier
    Unique identifier. Two templates with the same ID cannot exist at the same time. Also used for inheritance in other templates.

    - Kind
    Type template. For projects, Xcode.Xcode3.ProjectTemplateUnitKind is always used.

    - Concrete
    A field that indicates whether the template will be displayed in the list when creating a new application. It makes sense to set NO when it is called from another template and is not independent in itself. In other cases, always set YES.

    Optional fields:

    - Platforms
    Defines for which platforms the template is used. Useful only to prevent inheritance in templates for other platforms (for example, when trying to import a template for iOS into a template for WatchOS).

    - Name The
    display name for the template. The default directory name is * .xctemplate.

    - SortOrder
    Serial Number. If there is no such field, it is considered as the last.

    - Description
    Description of the template. In Xcode, the latest versions are not displayed.

    2. Inheritance
    Templates in Xcode have a very useful property: they can include properties and files from other templates. It is very useful if there is a need to expand the template with additional features from another, while not copying the files again and not editing the configuration file. A direct analogy is inheritance in OOP.

    3. Ancestors
    A list of Identifier templates whose properties and files will be included in the project.

    4. Content generation You can
    fill in a new application either with ready-made files or by registering their generation in the settings.

    PS Since projects can be created using both Objective-C and Swift, it must be borne in mind that file generation must be registered separately for different languages.
    To do this, the Options field is created, which is an array. As the first element, create a Dictionary and create two keys. The first is an Identifier of type String with the value "languageChoice". The second is Units, which is a Dictionary. In Units, we create two more Dictionary named “Objective-C” and “Swift”, respectively. All subsequent Definitions and Nodes are placed inside these directories. If there is no language binding (for example, we want to add xib, storyboard or write content for some file), then Definitions and Nodes can be declared at the same level with other parameters.



    5. Definitions
    Here the code generation is declared and the paths to the files to be added to the application are registered.

    Definitions is an associative array and contains a list of files or variables. Each file, in turn, is also an associative array that contains the path to the file. It can consist of two properties - Path and Group.

    Path - the direct path to the file, which is located in the .xctemplate directory.
    Group - an array, each element of which is a directory in the specified path. The file itself is not specified.

    For example, the file has a path:

    Presentation/Common/ViewController/Base/ViewController.swift

    Then the Definition for it will look like this:



    Accordingly, if the file has no nesting and lies directly in .xctemplate /, then the Group array is not created.

    6. Nodes
    After we have specified the file location paths, it is necessary to create links with which we will point either to the created file or to the contents. Nodes is a regular array whose elements are keys from Definitions. For the above example, Nodes would look like this:



    Code generation inside TemplateInfo.plist


    You can add code to the file created in TemplateInfo.plist by writing it in Definitions and linking to it in Nodes. This is done using the “:” operator after specifying the file, after which the code is written. For example, in the standard Page-Based App template, you can see that Definitions describes a lot of code generation:



    The order of the code in the file depends on the order of the links in the Nodes array. If the specified file does not exist, then it will be created.

    The following constants work in the previously created files and inside TemplateInfo.plist:

    ___COPYRIGHT___ Copyright line
    ___DATE___ Date of creation of the project (file)
    ___DIRECTORY___ Full path to the file
    ___FILEBASENAME___ File name without extension
    ___FILEEXTENSION___ File extension
    ___FILENAME___ Full name of the file
    ___FULLUSERNAME___ The name of the user authorized in the system
    ___ORGANIZATIONNAME___ The name of the organization specified when creating the project
    ___PACKAGENAME___ / ___PROJECTNAME___ The name of the account specified when the project
    was created
    ___IMEN_ER_NAME_ ________

    Editing application settings window


    When creating a template, you can also edit the application settings window, which will subsequently appear when this template is called.

    For example, for the “Single View App”, Apple offers us several text fields for entering the developer’s name and organization’s name, several checkboxes for inclusion in the unit test project or CoreData, as well as a drop-down list for choosing a programming language. All this is regulated by the Options field - an array from the Dictionary. The following list of options is available for each option:

    - Identifier
    Identifier by which you can change or use the value stored in the option field.

    - Default
    The value that will be used for this field by default.

    - SortOrder
    The serial number by which this option will be displayed in the window.

    - Nae
    Title for option.

    - Type The
    type of field to create. The following field types are available:

    • Static Static, uneditable text. In terms of meaning - nothing more than a Label.
    • Checkbox The usual checkbox. Since it is essentially a Bool field, it is also necessary for it to define Units, which will contain the corresponding set of actions for true and false values. An example of use can be seen in the core template “Core Data Cocoa Touch App.xctemplate”, which will be mentioned in the template creation section.
    • Text A field for entering text.
    • Popup. Provides a selection from the drop-down list that should be defined in the Values ​​array.

    Create an application template


    Before you begin, you need to prepare files with the written code that we want to see in the application created according to our template. If you don’t have your stock yet, you can take mine . This is the simplest implementation of MVVM without using any libraries. There are not many files here, but enough for an example. I will analyze the further creation of the template using their example.

    First, create a directory in which the templates we created will be stored. To do this, execute the command in the console

    $ mkdir -p ~/Library/Developer/Xcode/Templates/Project\ Templates/Private

    Xcode will search for application templates along this path. You can name the Private folder at your discretion, the main thing is that it is located along this path. There may be several such directories, but the templates enclosed in them must have a different Identifier. Otherwise, the existence of the template in all but one directory will be ignored.

    The previously copied “Single View App.xctemplate” is renamed to “MVVM Application.xctemplate” and copied to the Private folder. If you now start Xcode and go to the menu for creating a new application, you can already see the new Private section at the very bottom, where there will be one single “MVVM Application” template. Since we have not changed anything yet, when using it we get the same Single View App (which, by the way, disappeared from the list of basic ones, because it has the same Identifier).

    The next step is to move the Presentation folder and two icon files - TemplateIcon.png and TemplateIcon@2x.png. Now you need to change the Identifier so that Xcode sees our template as completely new. For example, define Identifier as “MVVMTemplate”. Now when creating a new application in Xcode, we will see that the “Single View App” has returned to its place, and in the Private section, “MVVM Application” with our icon flaunts.

    Next, let's see which templates the Single View App inherits from. Open TemplateInfo.plist and go to Ancestors, where we see: There are templates with these identifiers in the same place as the “Single View App”. Let's sort it out in order.

    com.apple.dt.unit.storyboardApplication
    com.apple.dt.unit.coreDataCocoaTouchApplication




    The first “Storyboard App.xctemplate” template contains only the configuration file, in which you can see the Definitions and Nodes fields. They stipulate that Main.storyboard will be used as the main storyboard, and the path to it will be indicated. We do not need this, because we already have the MainScreen.storyboard file that we want to use as the main one. Therefore, we remove the “Storyboard App.xctemplate” template from Ancestors.

    Next comes the “Core Data Cocoa Touch App.xctemplate” template. A checkbox field is added to its options for the ability to use CoreData, and the Units field contains all the necessary code generation and import of the ___ PACKAGENAMEASIDENTIFIER ___. Xcdatamodeld file. Suppose we don’t need CoreData either, and also delete this parent.

    But here is the problem: if we now try to create an application according to our template, then it will not be visible in the list. The fact is that the parents removed by us, in turn, also had the Ancestors list, which contained the necessary Cocoa Touch App Base template, which has the identifier com.apple.dt.unit.cocoaTouchApplicationBase. Adding it to the Ancestors list of our template, we will return it to the list of available ones again. Having carefully studied this basic template, you will understand why it is so necessary, and we move on.

    Now let's write down all the paths and links for the copied files. Since the code is written for Swift, I will do this only for him.

    Go to Options -> languageChoice (Item 0) -> Units -> Swift and create a Dictionary here called Definitions. Now we write out all the paths to the files that we have: We get the following list: Now we fill in the Nodes links, it will look like this: It remains to add the final touch - put MainScreen.storyboard as the main one. We create Definitions and Nodes for the whole file and add the following fields to them: Definitions: Key Info.plist: UIMainStoryboardFile Value

    Presentation/Common/View Controller/Base/ViewController.swift
    Presentation/Common/View Model/Base/ViewModel.swift
    Presentation/Common/View Model/ViewModelHolder.swift
    Presentation/Main Screen/MainScreen.storyboard
    Presentation/Main Screen/View Controller/MainViewController.swift
    Presentation/Main Screen/View Model/MainViewModel.swift


















    UIMainStoryboardFileMainScreen

    Nodes:
    Info.plist: UIMainStoryboardFile

    We get the following:



    In the example I attached, there is a ready-made version of the TemplateInfo.plist file.

    This article does not describe all the functions for creating templates and files. It is simply not possible to fit here a description of each parameter. Therefore, I put documentation (unofficial) in the repository in which the example lies, which describes all the features and lists all the existing parameters (at the time of the existence of Xcode 4). Most of the functions can be understood by delving into the basic templates from Apple, at the same time seeing their implementation. I just described the necessary minimum for the simple creation of uncomplicated templates.

    If you have any comments and additions, I will be glad to listen to them and supplement the article in order to increase its usefulness.

    Also popular now: