iOS组件化实践之:类命名注释篇
1.问题描述
CocoaPods组件创建时,提供的一个很好的管理命名规范的思路:以统一的命名前缀,一般以项目/组织等缩写作为前缀
组件化规整之后,可能存在的情况是前后的文件命名不一致导致的影响代码易读性、易维护等问题
除此之外,由于代码经由不同人迭代的,甚至不同组织迭代(从外包接手的项目)还存在一些文件注释的注释模板差异的情况
2. 类命名统一
2.1 类重命名之前
需要确认下,当前类或者与之相关的一些类,是否存在于CocoaPods公有源上,如果存在,可以直接通过Pod引入(组件内通过dependency),
举个例子:如果你需要进行重命名的类是这样的:SDWebImage、SDWebImageXXX、SDXXX,显然,这是将SDWebImage通过代码直接集成,由于SDWebImage类数量比较多,且属于成熟框架,在确认没有私自改动逻辑的情况下,可以考虑直接移除,采用通过Pod引入(组件内通过dependency)
当然,如果存在没有被用到的类,也正好是一个移除他们的好时机!
‼️特别注意:改名之前,需要确认,要改的类名是否已经存在工程中,如果存在且继续修改,会造成很多错误替换,造成很复杂的编译问题,且难以回退。
例如:ABCWebView,要改成PSCWebView,此时如果工程中已经存在PSCWebView,则ABCWebView继续再改成PSCWebView,会造成所有ABCWebView与PSCWebView的混乱,除非单次修改(之前的操作已经提交),否则回退也变得异常困难。
2.2 常规类重命名
可以通过IDE:Xcode自带的rename功能进行类名重命名:
替换成带期望前缀的类名
可能存在替换不完全的可能,需要检索下旧类名,全局替换下,确保编译通过方可
2.3 categories重命名
categories的重命名无法根据上述方式,只能通过常规的修改文件名,以及全局替换的方式。
值得一提的是,若一个基础类存在多个单一功能的categories,例如存在UIButton+Category1,UIButton+Category2……,他们有可能存在重复的功能可以考虑保留其中一个即可,也可以考虑将他们重构,合并,或者是重新划分下功能归属,
3.类注释模板统一:
治理这些情况,可能就需要分两步:
3.1 第一步:存量类注释规范治理
存量治理,这边采用脚本批量执行,具体思路如下:
- 遍历指定目录(若未传参数则为当前目录)下的子目录
- 匹配所有iOS工程类文件:.h .m .swift
- 对其注释头进行模板替换
- 匹配获取当前类的author,匹配不到则使用默认值(需定义)
- 匹配获取当前类的time,匹配不到则使用默认值(需定义)
- 替换版权信息(需定义)
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/bin/bash
# 遍历更新当前目录下(含子目录)所有iOS工程类文件:.h .m .swift 并对其注释头进行模板替换
# author: Chenyp34
# [目的]
#
# 组件化规整之后,可能存在的情况是前后的文件命名不一致导致的影响代码易读性、易维护等问题
# 除此之外,由于代码经由不同人迭代的,甚至不同组织迭代(从外包接手的项目)还存在一些文件注释的注释模板差异的情况
# 此脚本目的为了解决存量类文件头注释统一性问题
#
# [目录]
# - replace_class_header_anotation.sh 遍历更新当前目录下,子目录git仓库的脚本
#
# [说明]
# 1、遍历指定目录(若未传参数则为当前目录)下的子目录
# 2、匹配所有iOS工程类文件:.h .m .swift
# 3、对其注释头进行模板替换
#
# [参数]
# 1、参数1,指定目录
#
# [调用说明]
# 1、未指定目录,则取当前目录:sh replace_class_header_anotation.sh
# 2、指定目录:sh replace_class_header_anotation.sh /User/xxx/xx
# 本脚本适用于将:下述注释替换成 统一注释模板:
# 其一:
#//
#// FileName.h
#// ProjectName
#//
#// Created by Author on Date.
#// (没版权信息)
#//
#
# 其二:
# /****************************************************************************************************
# * 版权所有: Copyright (c) 2012-2021 xxxx. All rights reserved.
# * 作 者: Author (2021/3/12)
# * 界面描述: 界面描述
# ****************************************************************************************************/
#
# 其三:
# 没有任何注释的
#
#
# 替换成统一注释模板:
#
#//
#// "$filename"
#// "$project_name"
#//
#// Created by "$auth" on "$date".
#// "$copyright_str"
#//
#
#定义版权信息
export copyright_str="Copyright (C) 2023 Your Company Name Technology Limited. All rights reserved."
#定义默认用户信息:PaysonChen
export def_author_str="PaysonChen"
#定义默认日期:当前日期
export def_time_str=`date +%Y/%m/%d`
function get_creator_name_with_template_2() {
file=$1
creator_name=$(sed -n 's/.*作 者: \(.*\).*/\1/p' $file)
echo "creator_name="$creator_name" in file="$file
if [ -z "$creator_name" ]; then
echo '///获取创建者 第二种模板获取 为空 使用默认值'
creator_name=$def_author_str
fi
}
function get_creator_name() {
file=$1
creator_name=$(sed -n 's/.*Created by \(.*\) on.*/\1/p' $file)
if [ -z "$creator_name" ]; then
get_creator_name_with_template_2 $file
fi
echo "--------creator_name=【"$creator_name"】 in file="$file
}
function get_creator_time_with_template_2() {
file=$1
creator_time=$(sed -n 's/.*创建日期: \(.*\).*/\1/p' $file)
echo "-------创建日期=【"$creator_time"】 in file="$file
if [ -z "$creator_time" ]; then
# echo '///获取创建时间 第二种模板获取 为空 使用默认值'
creator_time=$def_time_str
fi
}
function format_creator_time() {
creator_time=$1
length=${#creator_time}
# 截取除最后一个字符外的部分
creator_time=${creator_time:0:length-1}
#echo "截去掉最后一个字符后的字符串: $creator_time"
}
function get_creator_time() {
file=$1
if [ -z "$2" ]; then
line=5
else
line=$2
fi
#creator_time=$(sed -n '5s/.*\(.\{10\}\)$/\1/p' $file)
creator_time=$(awk 'NR=='$line' {print $NF}' $file)
echo "-------creator_time=【"$creator_time"】 line = "$line" in file="$file
# date_regex='^(19|20)[0-9]{2}/(0?[1-9]|1[0-2])/(0?[1-9]|[1-2][0-9]|3[0-1]).$'
#date_regex='^(19[0-9]{2}|20[0-9]{2}|[0-9]{2})/(0?[1-9]|1[0-2])/(0?[1-9]|[1-2][0-9]|3[0-1]).$'
date_regex='^(19[0-9]{2}|20[0-9]{2}|[0-9]{2})([-/])(0?[1-9]|1[0-2])([-/])(0?[1-9]|[1-2][0-9]|3[0-1]).$'
# 进行正则匹配
if [[ $creator_time =~ $date_regex ]]; then
echo "日期格式正确,截断最后一个小数 ."
format_creator_time $creator_time
else
if [ -z "$2" ]; then
discount=1
new_line=$((line-discount))
echo "常规调用如果匹配不到的花,那么多一次,向上查找"$discount"行,进行递归:"$new_line
get_creator_time $file $new_line
else
echo "日期格式错误,执行第二种匹配"
get_creator_time_with_template_2 $file
fi
fi
echo "********creator_time=【"$creator_time"】 in file="$file
}
function replace_header_anoation() {
file=$1
#定义要替换的字符串
#文件名
filename=$(echo "$file" | sed 's#.*/##')
#项目名
project_name="PSCProject"
#还有从当前类中获取作者信息,获取不到取默认值
auth=$creator_name
#还有从当前类中获取作者信息,获取不到取默认值
date=$creator_time
#以下是替换的模板
new_content="//
// "$filename"
// "$project_name"
//
// Created by "$auth" on "$date".
// "$copyright_str"
//"
new_content_escaped=$(echo "$new_content" | sed 's/$/\\/') # 转义换行符
sed -i '' -e "1,7c\\
$new_content_escaped" "$file"
#还有几个问题待优化
#1、如果开头没有注释,则会直接覆盖,或者注释不足7行的
#2、日期正则如果不是以 YYYY/MM/DD or YY/MM/DD 其中/和-都适用
#2.1但是兼容2023/8/1这样的个位数日期),
#2.2如果日期是8/1/23 这样会导致识别错误 会被替换成今天的日期
}
# 统一类头注释
function unify_header_anoation() {
file=$1
#还有从当前类中获取作者信息,获取不到取默认值
get_creator_name $file
#还有从当前类中获取作者信息,获取不到取默认值
get_creator_time $file
#不传第二个参数 则执行替换,传就不执行
if [ -z "$2" ]; then
replace_header_anoation $file
fi
}
function main() {
file_path=$1
if [ -z "$file_path" ]; then
echo '///未指定路径,file_path为. 当前路径'
file_path=.
fi
#遍历当前路径下所有oc类
find $file_path -type f -name "*.swift" -o -name "*.h" -o -name "*.m" | while read file; do
unify_header_anoation $file $2
done
}
main $1 $2
3.2 第二步:新增类注释模板制定
增量治理,可以通过工程内部的内置的模板进行限定,具体操作为:
3.2.1 全局指定
全局指定在下列路径中新增文件名为:IDETemplateMacros.plist
其中内容为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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>
//
// ___FILENAME___
// ___PACKAGENAME___
//
// Created by ___FULLUSERNAME___ on ___DATE___
// ___COPYRIGHT___
//
</string>
</dict>
</plist>
路径(按优先级从低到高排序:如果更高一级优先级目录下出现了IDETemplateMacros,会覆盖比他低优先级的目录下的IDETemplateMacros内容)
xcWorkspace:
1
XXX.xcworkspace/xcshareddata/IDETemplateMacros.plist
xcodeproj(相比xcworkspace,具有更高优先级):
1
XXX.xcodeproj/xcshareddata/IDETemplateMacros.plist
xcodeproj下的xcshareddata文件夹下存在IDETemplateMacros.plist,会覆盖xcworkspace的xcshareddata,(也就是xcworkspace的xcshareddata的IDETemplateMacros.plist不生效)
**综上所述:xcworkspace下的IDETemplateMacros,在xcworkspace内部的xcodeproj未指定IDETemplateMacros时生效**
3.2.2 用户指定
上述xcodeproj、xcworkspace根目录下还有各自xcuserdata,xcuserdata内包含各个用户名的文件夹 username.xcuserdatad,存在此目录下的IDETemplateMacros.plist ,优先级高于xcshareddata,
1
2
XXX.xcworkspace/xcuserdata/IDETemplateMacros.plist
XXX.xcodeproj/xcuserdata/IDETemplateMacros.plist
优先级与2.2.1所述一致:xcworkspace/xcodeproj内的xcshareddata下的IDETemplateMacros,在xcworkspace/xcodeproj内部的xcuserdata未指定IDETemplateMacros时生效
3.2.3 本地指定
上述情况之外:
在上述均不存在IDETemplateMacros.plist时,本地目录才会生效:
1
/Users/Mac登录名/Library/Developer/Xcode/UserData/IDETemplateMacros.plist