0%

Xcode 文本宏(Text Macros)的介绍和应用

前言

文本宏(Text Macros)是Xcode隐藏的特性,直到Xcode 9.0后,苹果官方才开始允许开发者进行自定义文本宏。下面将会详细介绍文本宏的相关知识和应用场景。

什么是文本宏

文本宏(Text Macro)是一种可以就地展开(expanded in-place)为特定文本的符号。其常见于Xcode文件模板中,如图所示:

NSObjectObjective-C文件模板

图中的FILEHEADERFILEBASENAMEFILEBASENAMEASIDENTIFIER就是所说的文本宏。Xcode在使用文件模板创建文件时,会把文件模板中的文本宏,展开生成特定的文本,如使用NSObjectObjective-C文件模板创建一个文件名为MyObject.m的文件时,FILEHEADER会展开生成头部注释信息,FILEBASENAME会展开生成字符串MyObjectFILEBASENAMEASIDENTIFIER会展开生成字符串MyObject,如下图所示:

文本宏解释示例

延伸阅读

Xcode模板有文件模板和工程模板。模板文件按照开发平台存放,其中每个平台的模板位置如下:

  • macOS平台模板:/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates
  • iOS平台模板:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates
  • tvOS平台模板:/Applications/Xcode.app/Contents/D eveloper/Platforms/AppleTVOS.platform/Developer/Library/Xcode/Templates
  • watchOS平台模板:/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/Library/Xcode/Templates

公开可用的文本宏

当前Xcode在其官方文档公开给开发者可用的文本宏有以下几类:

时间类:

  • DATE

    当前的日期,如2018/12/20

  • YEAR

    四位数字格式的当前年数,如2018

  • TIME

    当前的时间,如20:48

开发环境类:

  • RUNNINGMACOSVERSION

    当前macOS系统的版本。

  • DEFAULTTOOLCHAINSWIFTVERSION

    当前工程使用的Swift版本。

  • FULLUSERNAME

    当前系统用户的全名。

  • USERNAME

    当前macOS用户的登录名。

开发工程配置类:

  • ORGANIZATIONNAME

    当前工程配置的公司名称。

  • WORKSPACENAME

    当前Workspace的名称。如果Workspace中只有一个 Project,那么这个宏的值便是当前打开的Project的名称。

  • PROJECTNAME

    当前工程的名称。

  • TARGETNAME

    当前Target的名称。

  • PACKAGENAME

    当前工程Scheme所设置的包名。

  • PACKAGENAMEASIDENTIFIER

    把不符合C语言标识符规范的字符替换为下划线(_)后的PACKAGENAME

  • PRODUCTNAME

    当前工程Scheme设置的应用名称。

  • COPYRIGHT

    当前工程的版权信息,如Copyright © 2018 YK-Unit. All rights reserved.

    需要注意的是,若当前Xcode工程没有配置公司名,该值会是一个空字符串。

文本文件信息类:

  • FILENAME

    当前文件的完整名称,包括扩展名。

  • FILEBASENAME

    删除掉扩展名后的FILENAME,如创建一个名为MyObject.m的文件,该值为MyObject

  • FILEBASENAMEASIDENTIFIER

    把不符合C语言标识符规范的字符替换为下划线(_)后的FILEBASENAME,如创建一个名为My-Object.m的文件,该值为My_Object

    注:C语言标识符规范只允许使用字母(A-Z, a-z)和数字(0-9)以及下划线(_),使用这个宏会把其他的字符自动替换成下划线。

  • FILEHEADER

    每个文本文件头部的文本。

    注:该文本宏其实是由多个文本宏组成,其首先是展开生成以下文本:

    1
    2
    3
    4
    5
    6
    //  ___FILENAME___
    // ___PACKAGENAME___
    //
    // Created by ___FULLUSERNAME___ on ___DATE___.
    // ___COPYRIGHT___
    //

    之后Xcode再把上述的宏文本展开生成对应的文本,最后生成的就是我们日常看到的文件头部注释信息了。

其他:

  • NSHUMANREADABLECOPYRIGHTPLIST

    macOS app工程的target中的Info.plist 文件中人类可读的版权信息条目的值,该值包括这个条目的keyvalue以及XML的分隔符,如:

    1
    2
    <key>NSHumanReadableCopyright</key>
    <string>Copyright © 2017 Apple, Inc. All rights reserved.</string>
  • UUID

    使用这个宏的时候,会返回一个唯一ID。具体应用场景待探索。

如何使用文本宏

使用文本宏的方式很简单,只需要在文本宏之前和之后添加三条下划线(_)即可,如使用FILENAME文本宏:

1
___FILENAME___

如何格式化文本宏的值

文本宏展开生成的值,不一定符合开发要求,如创建文件时,开发者输入的文件名带有非法的字符。为此,Xcode通过提供修饰符(modifier)来对文本宏的值进行格式化。使用修饰符的方法如下:

1
<MACRO>:<modifier>[,<modifier>]…

文本宏和修饰符之间用分号(:)分隔。多个修饰符之间可以用逗号(,)分隔。

把文本宏和特定的修饰符结合起来后,就可以修改文本宏的最终值,如下面这段宏可以删除掉的FILENAME的扩展名以及使用下划线(_)替换掉不符合C标识符的字符:

1
FILENAME:deletingPathExtension,identifier

这时候的FILENAME:deletingPathExtension,identifier等同于FILEBASENAMEASIDENTIFIER

当前Xcode提供的修饰符有:

  • identifier

    用下划线(_)替换所有不符合C语言标识符规范的字符。

    注:C语言标识符规范只允许使用字母(A-Z, a-z)和数字(0-9)以及下划线(_

  • bundleIdentifier

    用连字符(-)替换所有不符合bundle标识符规范的字符。

    注:bundle标识符规范只允许使用字母(A-Z, a-z)和数字(0-9)以及连字符(-)。

  • rfc1034Identifier

    用连字符(-)替换所有不符合rfc1034标识符规范的字符

  • xml

    将一些特殊的XML字符用其转义字符替换。如,<会被 &lt 替换。

  • deletingLastPathComponent

    从展开的字符串中删除最后一个路径组件 (path component)。

  • deletingPathExtension

    从展开的字符串中删除扩展名。

  • deletingTrailingDot

    删除所有句子末尾的句点(.

  • lastPathComponent

    仅返回字符最后一个路径组件。

  • pathExtension

    返回字符的扩展名。

文本宏的应用

从Xcode 9.0开始,开发者可以自定义文本宏(覆盖已有的文本宏或者添加新的文本宏)。但是,实际开发中,文本宏的应用场景很少,目前暂时只发现了2个应用场景(若有其他场景,欢迎补充):

  • 自定义文件头部注释
  • 给创建的类都添加统一前缀

下面将会演示如何如何实现上述场景。

但是,在这之前,开发者需要创建一个名为IDETemplateMacros.plist的文件,并把文件放置在下面文件目录列表中的一个

注意:

  • 不同位置具有不同的影响范围。
  • IDETemplateMacros.plist文件可以放置到以下几个位置中的任何一个。但是建议只放置在一个地方。
  • 当存在多个IDETemplateMacros.plist文件时,Xcode只会使用最先找到的IDETemplateMacros.plist
  • Project user data位置:

    <ProjectName>.xcodeproj/xcuserdata/[username].xcuserdatad/IDETemplateMacros.plist

    影响范围:对当前 Project 指定的用户(username)创建的文件有影响

  • Project shared data位置:

    <ProjectName>.xcodeproj/xcshareddata/IDETemplateMacros.plist

    影响范围:对当前 Project 的所有成员创建的文件有影响

  • Workspace user data位置:

    <WorkspaceName>.xcworkspace/xcuserdata/[username].xcuserdatad/IDETemplateMacros.plist

    影响范围:对当前的 Workspace 下的指定的用户(username)创建的文件有影响

  • Workspace shared data位置:

    <WorkspaceName>.xcworkspace/xcshareddata/IDETemplateMacros.plist

    影响范围:对当前 Workspace 下的所有成员创建的文件有影响

  • User Xcode data位置:

    ~/Library/Developer/Xcode/UserData/IDETemplateMacros.plist

    影响范围:对当前 Xcode 创建的文件都有影响

自定义文件头部注释

Xcode文件模板中,使用FILEHEADER文本宏来展开生成头部注释,所以只需要在IDETemplateMacros.plist中重定义FILEHEADER即可。编辑后的IDETemplateMacros.plist如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?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>FILEHEADER</key>
<string>
// __ _,--="=--,_ __
// / \." .-. "./ \
// / ,/ _ : : _ \/` \
// \ `| /o\ :_: /o\ |\__/
// `-'| :="~` _ `~"=: |
// \` (_) `/
// .-"-. \ | / .-"-.
//.------------------{ }--| /,.-'-.,\ |--{ }-----------------.
// ) (_)_)_) \_/`~-===-~`\_/ (_(_(_) (
//
// File Name: ___FILENAME___
// Product Name: ___PRODUCTNAME___
// Author: ___AUTHOR___
// Swift Version: ___DEFAULTTOOLCHAINSWIFTVERSION___
// Created Date: ___DATETIME___
//
// Copyright © ___YEAR___ ___ORGANIZATIONNAME___.
// All rights reserved.
// ) (
//'--------------------------------------------------------------------'
</string>
<key>AUTHOR</key>
<string>___USERNAME___@___ORGANIZATIONNAME___</string>
<key>DATETIME</key>
<string>___DATE___ ___TIME___</string>
</dict>
</plist>

注意:示例中不止是重定义FILEHEADER,还新增了新的文本宏AUTHORDATETIME

这时候使用Xcode创建的文本文件的头部注释如下:

注释中的dog图形是使用命令行字符形状工具boxes生成。

boxes支持创建各种字符形状,有兴趣的童鞋不妨去探索下。

给创建的类都添加统一前缀

Xcode文件模板中,使用FILEBASENAMEASIDENTIFIER文本宏来展开生成类名,所以只需要在IDETemplateMacros.plist中重定义FILEBASENAMEASIDENTIFIER即可。编辑后的IDETemplateMacros.plist如下:

1
2
3
4
5
6
7
8
<?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>FILEBASENAMEASIDENTIFIER</key>
<string>YK___FILENAME:deletingPathExtension,identifier___</string>
</dict>
</plist>

这时候使用Xcode创建的一个类时,类的前缀都是以YK开头,如图所示:

参考资料