美文网首页iOS
Xcode9文件模板——第一篇

Xcode9文件模板——第一篇

作者: 纸简书生 | 来源:发表于2018-07-23 17:55 被阅读314次

    之前写过一篇关于iOS如何自定义文件/项目模板。很多同学看了之后并没有理解如何去实现一套自己的模板。为了方便大家理解,我在Xcode9基础之上重新梳理一遍,由浅入深,希望帮到需要的同学。

    自定义模板的场景

    如果使用自定义文件模板来创建文件相对于使用代码块(Code Snip)相比要重量级一些。

    • 代码块适合于一行或多行代码,比如@property (nonatomic, strong) <#type#> <#name#>;
    • 文件模板更加适合用一个文件的整个内容模板化,比如控制器经常有很多相同的内容、声明周期、注册通知、处理通知、配置视图等等。这样就不用没写一个控制器都还需要重复写代码。

    代码块的使用读者自行搜索,很简单,值得一提的就是在需要自定义输入参数的时候是使用<#param#>占位。

    下面正式开始介绍Xcode9中如何自定义文件模板。

    解析Template

    如果想要充分理解Template,建议先看看Customizing the file header comment and other text macros in Xcode 9

    大致内容如下:

    • Xcode自带的文件头是完全是多余的,比如文件名、时间、作者等完全可以通过版本控制工具看到。
    • 在Xcode9中,允许开发使用文本宏的Plist自定义文件头。苹果官方链接——Customize text macros,其中所引用到的所有文本宏Text macros reference
      image
    • 可以根据作用范围,在不同的路径定义IDETemplateMacros.plist文件来限制自定义的范围。

    Text Macros

    在正式开始介绍前,先看看Text Macros 它定义了在创建文件的时候,文件名、创建时间等宏定义。也就是起到一个参数传递的作用

    DATE
    The current date.
    
    DEFAULTTOOLCHAINSWIFTVERSION
    The version of Swift used for the default toolchain.
    
    FILEBASENAME
    The name of the current file without any extension.
    
    FILEBASENAMEASIDENTIFIER
    The name of the current file encoded as a C identifier.
    
    FILEHEADER
    The text placed at the top of every new text file.
    
    FILENAME
    The full name of the current file.
    
    FULLUSERNAME
    The full name of the current macOS user.
    
    NSHUMANREADABLECOPYRIGHTPLIST
    The entry for the human readable copyright string in the Info.plist file of a macOS app target. The value of the macro must include the XML delimiters for the plist. For example, a valid value is:
    
    <key>NSHumanReadableCopyright</key>
    
    <string>Copyright © 2017 Apple, Inc. All rights reserved.</string>
    
       
    
    Notice that the value includes a newline.
    
    ORGANIZATIONNAME
    The company name for the team used for the provisioning profile.
    
    PACKAGENAME
    The name of the package built by the current scheme.
    
    PACKAGENAMEASIDENTIFIER
    A C-identifier encoded version of the package name built by the current scheme.
    
    PRODUCTNAME
    The app name of the product built by the current scheme.
    
    PROJECTNAME
    The name of the current project.
    
    RUNNINGMACOSVERSION
    The version of macOS that is running Xcode.
    
    TARGETNAME
    The name of the current target.
    
    TIME
    The current time.
    
    USERNAME
    The login name for the current macOS user.
    
    UUID
    Returns a unique ID. The first time this macro is used, it generates the ID before returning it. You can use this macro to create multiple unique IDs by using a modifier. Each modifier returns an ID that is unique for that modifier. For example, the first time the UUID:firstPurpose modifier is used, the macro generates and returns a unique ID for that macro and modifier combination. Subsequent uses of the UUID:firstPurpose modifier return the same ID. Adding the UUID:secondPurpose modifier generates and returns a different ID that will be unique to UUID:secondPurpose, and different from the ID for UUID:firstPurpose.
    
    WORKSPACENAME
    The name of the current workspace. If there is only one project open, then the name of the current project.
    
    YEAR
    The current year as a four-digit number.
    

    模板路径

    一般情况下自定义的文件模板在~/Library/Developer/Xcode/Templates/File Templates/<Custom Group Name>。可以有多个自定义的文件模板组。

    系统文件模板在~/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Templates经过测试如果把自定义文件模板放在系统的文件模板目录下同样可以使用。

    这里就以XLFile为自定义文件模板组。在该目录下创建XLCocoa Class.xctemplate文件夹,在XLCocoa Class.xctemplate就是包含具体的文件模板。

    XLFile
        └── XLCocoa\ Class.xctemplate
    

    最简单的文件模板

    ___FILEBASENAME___.h中的内容如下

    //___FILEHEADER___
    
    #import <Foundation/Foundation.h>
    
    @interface ___FILEBASENAMEASIDENTIFIER___ : NSObject
    
    @end
    

    ___FILEBASENAME___.m文件中的内容

    //___FILEHEADER___
    
    //Simple File Template
    #import "___FILEBASENAME___.h"
    
    @implementation ___FILEBASENAMEASIDENTIFIER___
    
    @end
    
    • 注意上面的___FILEBASENAMEASIDENTIFIER______FILEBASENAME___就是Xcode提供的文本宏。

    接下来是设置TemplateInfo.plist文件,其内容如下

    <?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.IDEFoundation.TextSubstitutionFileTemplateKind</string>
    </dict>
    </plist>
    
    • TemplateInfo.plist至少需要一个Kindkey,并且是字符串类型,一般情况下的值用Xcode.IDEFoundation.TextSubstitutionFileTemplateKind就可以了。虽然还有另外的值选择比如CoreData中的Xcode.IDECoreDataModeler.ManagedObjectTemplateKind,实际中其实根本用不到。

    现在新建文件拖到最下面就会看到如下的结果:


    15323344441516.jpg

    创建之后的内容如下:

    //
    //  SimpleTemplate.h
    //  NoteForCode
    //
    //  Created by xxx on 2018/7/23.
    //  Copyright © 2018年 wesly. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface SimpleTemplate : NSObject
    
    @end
    

    .m

    //
    //  SimpleTemplate.m
    //  NoteForCode
    //
    //  Created by xxxx on 2018/7/23.
    //  Copyright © 2018年 wesly. All rights reserved.
    //
    
    //Simple File Template
    #import "SimpleTemplate.h"
    
    @implementation SimpleTemplate
    
    @end
    

    TemplateInfo.plist的Key

    TemplateInfo.plist有很多的key来解释模板文件的结构或者内容。在最简单的模板文件中我们只使用了Kind这个Key。下面是我从Xcode自带的文件模板截取出来的plist文件内容。

    <?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.IDEFoundation.TextSubstitutionFileTemplateKind</string>
        <key>Description</key>
        <string>A Cocoa class.</string>
        <key>Summary</key>
        <string>A Cocoa class</string>
        <key>SortOrder</key>
        <string>1</string>
        <key>DefaultCompletionName</key>
        <string>MyClass</string>
        <key>Platforms</key>
        <array>
            <string>com.apple.platform.macosx</string>
        </array>
        <key>Options</key>
        <array>
            <dict>
                <key>Identifier</key>
                <string>productName</string>
                <key>Required</key>
                <true/>
                <key>Name</key>
                <string>Class:</string>
                <key>Description</key>
                <string>The name of the class to create</string>
                <key>Type</key>
                <string>text</string>
                <key>NotPersisted</key>
                <true/>
            </dict>
            <dict>
                <key>Identifier</key>
                <string>cocoaSubclass</string>
                <key>Required</key>
                <true/>
                <key>Name</key>
                <string>Subclass of:</string>
                <key>Description</key>
                <string>What class to subclass in the new file</string>
                <key>Type</key>
                <string>class</string>
                <key>Default</key>
                <string>NSObject</string>
                <key>FallbackHeader</key>
                <string>#import &lt;Cocoa/Cocoa.h&gt;</string>
                <key>Values</key>
                <array>
                    <string>NSObject</string>
                    <string>NSDocument</string>
                    <string>NSView</string>
                    <string>NSViewController</string>
                    <string>NSWindowController</string>
                </array>
            </dict>
            <dict>
                <key>Identifier</key>
                <string>XIB</string>
                <key>Name</key>
                <string>Also create XIB file for user interface</string>
                <key>Description</key>
                <string>Whether to create a XIB file with the same name</string>
                <key>Type</key>
                <string>checkbox</string>
                <key>RequiredOptions</key>
                <dict>
                    <key>cocoaSubclass</key>
                    <array>
                        <string>NSDocument</string>
                        <string>NSViewController</string>
                        <string>NSWindowController</string>
                    </array>
                </dict>
                <key>Default</key>
                <string>true</string>
                <key>NotPersisted</key>
                <true/>
            </dict>
            <dict>
                <key>Identifier</key>
                <string>languageChoice</string>
                <key>Required</key>
                <true/>
                <key>Name</key>
                <string>Language:</string>
                <key>Description</key>
                <string>The implementation language</string>
                <key>Type</key>
                <string>popup</string>
                <key>Default</key>
                <string>Objective-C</string>
                <key>Values</key>
                <array>
                    <string>Swift</string>
                    <string>Objective-C</string>
                </array>
                <key>MainTemplateFiles</key>
                <dict>
                    <key>Swift</key>
                    <string>___FILEBASENAME___.swift</string>
                    <key>Objective-C</key>
                    <string>___FILEBASENAME___.m</string>
                </dict>
                <key>AllowedTypes</key>
                <dict>
                    <key>Swift</key>
                    <array>
                        <string>public.swift-source</string>
                    </array>
                    <key>Objective-C</key>
                    <array>
                        <string>public.objective-c-source</string>
                        <string>public.objective-c-plus-plus-source</string>
                    </array>
                </dict>
            </dict>
        </array>
    </dict>
    </plist>
    

    下面对其中的某些key进行说明。其实完全可以根据Xcode自带的模板来猜测相应key的作用。

    • Description、Summary:用于提示。但是现在的Xcode没有使用这些两个key了。
    • DefaultCompletionName:默认文件名(字符串类型),用于显示在保存对话框中的默认文件名。
    • AllowedTypes:文件可用类型(字符串数据),用于确定哪些文件类型可以被保存,其值是一个UTI类型。关于UTI得详细内容可以看看这里System-Declared Uniform Type Identifiers。下面是一些常用的UTI
      • public.swift-source
      • public.c-header
      • public.c-source
      • public.c-plus-plus-source
      • public.objective-c-source
      • public.objective-c-plus-plus-source
    • Platforms(字符串数组):用于确定在某些平台可以使用该模板。该模板只会设置了该值的面板中显示。如果不设置那么每个平台下都会有该模板。值有如下几种:
      • com.apple.platform.macosx
      • com.apple.platform.iphoneos
      • com.apple.platform.watchos
      • com.apple.platform.appletvos

    图标

    最后还可以设置一下模板的图标,给人看起来逼格更高。具体来讲图标名称:

    • TemplateIcon.png (48 ⨯ 48)
    • TemplateIcon@3x.png (96 ⨯ 96)

    比如用了这个图标:



    最终在创建文件的时候就会长这样子


    不同的形式

    单类文件

    多类文件

    上面的例子是创建了单个的类文件。其实还可以一次创建多个文件,根据输入的文件名称。比如一次性根据输入的Model名,创建好对应头文件、View、ViewModel、Xib文件等
    比如在刚才的目录下创建如下文件:


    然后创建文件,输入Person得到如下这些文件

    多模板

    多模板其实就是在前面的基础上再建一层子文件夹。类似于:


    相关文章

      网友评论

      • LD_X:以前做的一个模板,类似创建一个个模块那种(类似MVC三个文件夹,里面对应的控制器,Model之类的,也像自定义项目里面的文件夹名字自定义了,然后类名使用这二个宏,___FILEBASENAME___VC,___FILEBASENAME___Model,类里面使用___FILEBASENAMEASIDENTIFIER___),以前可以使用。公司的新电脑拉到Xcode9.3里面,类名突然多了点东西___FILEBASENAMEASIDENTIFIER___这个宏,感觉___FILEBASENAMEASIDENTIFIER___这个宏是不是有变化了?楼主有碰到这种类似突然不能用的问题哇?
        LD_X:@纸简书生 好的,谢谢
        纸简书生:@LD_X 我还没有遇到过,这个其实就是___FILEBASENAMEASIDENTIFIER___ 含义就是The name of the current file encoded as a C identifier.没有变化,你检测一下写法!具体链接:https://help.apple.com/xcode/mac/9.0/index.html?localePath=en.lproj#/dev7fe737ce0
      • 翻滚的炒勺2013:我太笨了 这么详细了 我还是没看明白

      本文标题:Xcode9文件模板——第一篇

      本文链接:https://www.haomeiwen.com/subject/hgwjmftx.html