Xcode插件: 编码效率神器 FlyCoding

image

FlyCoding - Xcode版 Emmet

⚠️ 请使用 Swift 5 编译 ⚠️

FlyCoding 是一个 Xcode 插件,使用苹果提供的插件机制编写,可以运行在最新的Xcode上, 它提供了类似于前端中 Emmet 的功能。你可以通过特殊语法来快速的生成你想要的 Swfit / Objective-C 代码,特别是在大量的编写界面 UI 时, 重复的编写 UI 控件和约束是一件非常繁琐和机械的劳动, 但是这又是你不可避免的。
而 FlyCoding 则可以帮助你快速的生成属性、方法、约束(Masonry / SnapKit),目前 FlyCoding 刚刚发布了第一个版本,更多的功能还在构思当中,希望大家提供宝贵的意见和想法。

目前开发进度:
  • 2.0 版本中新增加强大的 @do 命令, 通过类shell命令对文本进行操作
    • remove 命令
    • to 命令
    • copy 命令
    • move 命令
    • sort 命令
  • Objective-C / Swift 属性生成
  • Objective-C / Swift 视图的快速创建
  • Masonry / SnapKit 约束生成
  • Swift 下的系统原生的 AutoLayout 约束
  • 快速生成方法
  • 任何完整操作都可以使用 ' + ' 进行分隔, 使用 '* N' 进行批量操作

生成 Snipkit 布局代码示例

image

@do 命令

@do move 10 34 to 44
// 将 10 行到 34 行的内容移动到 44 行
//
//命令的使用方法非常的简单,你可以任何地方直接编写命令
//命令以 @do 开头,接下来是你要操作的命令
//这里的 move 是移动命令,接下来饿 10 是起始行 34 是结束行
//to 也是一个命令,它是负责将内容移动到指定的位置
//to 并不是 move 命令的组合命令,它是一个独立的命令,详细的会在 to 命令中介绍中
//接下来是 to 命令的参数

理论上可以衔接无限制的命令数量,每个命令都是独立处理的单元,处理完毕后会通过一个通用的 context 进行状态传递,随着命令越来越多,一定会有更多神奇的连接用法。

删除命令

  • remove/rm
    • @do rm 10 .
    • arg1 [arg2]
      • arg1 表示起始行数
      • arg2 表示结束行数,此参数可以为空,此时 arg1 表示要删除的行
      • 除了可以使用 数字 表示行数外,也可以通过 . 来代表命令的当前行

移动命令

  • move/mv
    • @do mv 10 . to 30
    • arg1 [arg2]
      * arg1 表示起始行数
      * arg2 表示结束行数,此参数可以为空,此时 arg1 表示要移动的行
      * 除了可以使用 数字 表示行数外,也可以通过 . 来代表命令的当前行
    • to arg1
      * to 移动到指定位置需要配合 to 命令
      * arg1 表示要移动到的行

拷贝命令

  • copy/cp
    • @do cp 10 . to 30
    • arg1 [arg2]
      * arg1 表示起始行数
      * arg2 表示结束行数,此参数可以为空,此时 arg1 表示要拷贝的行
      * 除了可以使用 数字 表示行数外,也可以通过 . 来代表命令的当前行
    • to arg1
      * to 移动到指定位置需要配合 to 命令
      * arg1 表示要移动到的行

排序命令

将范围内的代码根据每行的长度,按照从少到多排列

  • sort/st
    • `@do st 10 .
    • arg1 [arg2]
      • arg1 表示起始行数, 如果 arg2 为空则表示结束行为命令当前行,而开始行表示命令当前行减去 arg1
      • arg2 表示结束行数,此时 arg1 表示结束行
      • arg2 除了可以使用 数字 表示行数外,也可以通过 . 来代表命令的当前行

属性生成

Swift属性生成

  • 单个属性
pv.UIImageView
// pv 是属性控制,p 是 private, v 是 var,具体的列表可以在后文中查看; . 用于区分属性和类名
private var <#name#>: UIImageView

Pv.Int/age
// Pv: public var
// `/age` 这里的 `/` 用来标记属性名
public var age: Int
  • 可选属性
fv.UILabel?
// fv 是属性控制, f 是 fileprivate, v 是 var; ?表示属性是可选的
fileprivate var <#name#>: UILabel?
  • 有默认值的属性
Pl.UIView{}
// Pl 是属性控制, P 是 public, l 是 let; {} 表示有默认值
// 默认值使用 Class() 来生成
// 如果有默认值,就不会再显示类型,因为 Swift 可以自己推断类型
public let <#name#> = UIView()


Pl.Int{100}
// 如果在 {} 里面添加默认值,会直接使用此默认值
public let <#name#> = 100
  • 懒加载属性
lv.UIButton
// lv 是属性控制,lv 是一个特殊的组合,分来时 l 表示 let, v 表示 var; 合并在一起时表示 lazy var
lazy var <#name#>: UIButton = {
    <#code#>
}()
  • OC可访问属性
@Pv.UIImageView
// 添加 @ 将把属性标记为 @objc
@objc public var <#name#>: UIImageView
  • 特殊的属性标识
 wv.EatProtocol?
// 添加 w 将把属性标记为 weak, 除了 w 之外,还有 u/unowned、 c/class 和 s/static
weak var <#name#>: EatProtocol?
  • 批量生成属性
pl.UILabel{} *2
// *2 中间不能有空格, 一般用于编写数据模型,或是编写 UI 时使用
private let <#name#> = UILabel()
private let <#name#> = UILabel()
  • 生成block初始化值
plb.UIButton
// 标记 b 表示的是 block 的意思
private let <#name#>: UIButton = {
    <#code#>
}()

Tips: 如果属性没有写标记,会自动使用 let 来标记属性

.UIImageView 

 let <#name#>: UIImageView

Swift 属性标记快速查询表

符号 标记
l Let
v var
lv lazy var
p private
P public
o open
f fileprivate
pl private let
pv private var
plv private lazy var
Pl public let
Pv public var
Plv public lazy var
ol open let
ov open var
olv open lazy var
fl fileprivate let
fv fileprivate var
flv fileprivate lazy var
-- --
@ @objc
u unowned
w weak
c class
s static
特殊符号 功能
b block, 为属性生成block形式的初始化值,类似于 lazy var
F 自用,属性的初始值是由 config 函数来提供的

Objective-C属性生成

Objective-C 中的使用语法和 Swift 区别不大,主要是关键字和生成的样子不同

  • 单个属性
.UIImageView *
// 默认描述就是 nonatomic, strong
@property (nonatomic, strong) UIImageView *<#name#>
  • 生成完整属性
c.NSString *name;
// 如果在末尾添加 ' ; ' 表示 Class 后面已经衔接了属性名, 为了方便快速编码
@property (nonatomic, copy) NSString *name;

Tips: class 可以用来标记类属性

Objective-C 属性标记快速查询表

符号 标记
s strong
w weak
a assign
r readonly
g getter=<#getterName#>
c copy
n nullable
N nonnull
c class

生成约束代码

我选取了最常用的两个框架来实现, 在 Objective-C 中使用 Masonry,而在 Swift 当中使用 SnapKit。

SnapKit

  • 添加布局
 #snpm(iconView, e=self)
 // snpm 就是 makeConstraints, 在 () 中使用,号来分割各个语句
 // 第一个参数是要添加约束的对象,剩下的都是布局语句
 // 每个语句都分为三个部分,左边是被约束对象的属性,中间是约束方式,
 // 而右边是约束的值或是其它的约束对象
 iconView.snp.makeConstraints {
    $0.edges.equalTo(self)
 }
  • 更新布局
#snpu(iconView, h=100)
// snpu 是 updateConstraints
iconView.snp.updateConstraints {
    $0.height.equalTo(100)
}
  • 重置布局
#snprm(iconView, r=self - 20)
// snprm 是 remakeConstraints
iconView.snp.remakeConstraints {
    $0.right.equalTo(self).offset(-20)
}
  • 布局演示 1 (相对距离)
#snpm(iconView, r=titleLabel.l-20, wh=20)
// 更加直观的使用 + - 来进行相对距离的设置
iconView.snp.makeConstraints {
    $0.right.equalTo(titleLabel.snp.left).offset(-20)
    $0.width.height.equalTo(20)
}
  • 布局演示 2 (+-的作用)
#snpm(iconView, t=titleLabel.b-superView.height-20, wh=100)
// 在约束语句中,第一个加减号除了有正负的含义,还是分割前后语句的标记
 iconView.snp.makeConstraints {
    $0.top.equalTo(titleLabel.snp.bottom).offset(-superView.height-20)
    $0.width.height.equalTo(100)
}
  • 布局演示 3 (比例约束)
#snpm(iconView, wh=self/2)
// 进行比例约束也是常用的约束手法
iconView.snp.makeConstraints {
    $0.width.height.equalTo(self).dividedBy(2)
}

// 相同作用 
#snpm(iconView, wh=self*0.5)
// 使用 * 法当然也是可以的
iconView.snp.makeConstraints {
    $0.width.height.equalTo(self).multipliedBy(0.5)
}
  • 布局演示 4 (比较)
#snpm(titleLabel, tl=self, r<=self - 20)
// 常用的根据文本的长度自适应宽度
// 也可以使用 >= 表示大于等于
 titleLabel.snp.makeConstraints {
    $0.top.left.equalTo(self)
    $0.right.lessThanOrEqualTo(self).offset(-20)
}
  • 布局演示 4 (约束等级)
#snpm(iconView, l = self, r <= superView~20, r <= titleLabel.l - 20~h)
// 在约束语句的最后使用 ~ 可以用来设置约束登记
// 你可以使用数字来表示约束登记,也可以使用 r\h\m\l 来标记
 iconView.snp.makeConstraints {
    $0.left.equalTo(self)
    $0.right.lessThanOrEqualTo(superView).priority(20)
    $0.right.lessThanOrEqualTo(titleLabel.snp.left).offset(-20).priority(.high)
}

SnapKit 属性标记快速查询表

  • 属性
符号 属性
l left
t top
b bottom
r right
w width
h height
x centerX
y centerY
c center
s size
e edges
--- 约束等级
r .required
h .high
m .medium
l .low
--- 比较参数
>= greaterThanOrEqualTo
<= lessThanOrEqualTo
= equalTo
--- 运算符号
- Offset(-value)
+ Offset(value)
* multipliedBy(value)
/ dividedBy(value)

Masonry

主要的用法和 SnapKit 一致, 下面主要说不同点

  • 创建、更新、重置
@masm(iconView, e=self)   // 创建
@masu(iconView, e=self)    // 更新
@masrm(iconView, e=self)  // 重置

Tips: 在 OC 中可以使用 @ 作为命令的前缀,主要是 # 在OC文件中会自动变第一列, 影响代码结构

  • 约束中没有 r 这个等级了
  • 比较里面新加了 == / >== / <==, 主要是相比少一个 = 的版本,在前面加上了 mas_
@masm(iconView, e=self)   // 创建
@masu(iconView, e=self)    // 更新
@masrm(iconView, e=self)  // 重置

AutoLayout(Swift)

主要的用法和 SnapKit/Masonry 一致, 下面主要说不同点

  • 使用 #layout 来执行语句
  • 移除了 s(size) / c(center) / e(edges) 的支持, 在以后的版本更新当中会重新添加回来
  • 移除了约束中除法的运算不能再使用 /
  • 对于偏移的控制不在简单的使用+``-, 如果想要设置常量约束或是偏移使用 :100 的形式
@layout(view, l=self:100, t=self:-20, w=self*2, h=:50)

视图的快速创建

这部分使用 Xcode 的代码块也可以实现,但是写代码的时候,打出了对应的短语后还要看一眼和等待Xcode反应实在是令人着急。我们为的就是快!!!并且我们可以直接赋予视图一个变量名,而代码块还是不行的

通过 #make 命令我们可以快速的添加创建一个 View 的代码

这是目前支持的创建类型

  • UIView

  • UILabel

  • UIButton

  • UIImageView

  • UITableView

  • UICollectionView

  • 普通创建 UIImageView

#make(UIImageView)
// 生成 Swift 视图
let <#name#>  = UIImageView()
<#name#>.backgroundColor = <#color#>
<#name#>.image = <#image#>
<#superView#>.addSubview(<#name#>)
// 生成 OC 视图
UIImageView *<#name#> = [[UIImageView alloc] init];
self.<#name#> = <#name#>;
<#name#>.backgroundColor = <#color#>;
<#name#>.image = <#image#>;
[<#superView#> addSubview: <#name#>];
  • 设置属性名创建 UILabel
@make(UILabel, titleLabel)
// 生成 Swift 视图
let titleLabel = UILabel()
titleLabel.font = <#font#>
titleLabel.textColor = <#color#>
titleLabel.text = <#text#>
titleLabel.backgroundColor = <#color#>
<#superView#>.addSubview(titleLabel)
// 生成 OC 视图
UILabel *titleLabel = [[UILabel alloc] init];
self.titleLabel = titleLabel;
titleLabel.font = <#font#>;
titleLabel.textColor = <#color#>;
titleLabel.text = <#text#>;
titleLabel.backgroundColor = <#color#>;
[<#superView#> addSubview:titleLabel];

创建方法

Swift

  • 创建方法

#func 可以使用 #f 缩写

#func(eat)
// 生成一个简单的方法
func eat() {
    <#code#>
}
  • 设定权限的方法
#func(@p.run)
// 标记和属性一样
@objc private func run() {
    <#code#>
}
  • 有参数的方法
#func(run::)
// 一个 : 代表有一个参数
func run(<#name#>: <#type#>, <#name#>: <#type#>) {
    <#code#>
}
  • 有返回值的方法
#func(run>)
// 一个 > 代表有一个返回值
func run() -> <#return#> {
    <#code#>
}
// 多个返回值会返回元组
#func(run>>)
func run() -> (<#return#>, <#return#>) {
    <#code#>
}

Objective-C

  • 创建方法
#func(run)
// 生成一个简单的方法
- (void)run {
    <#code#>
}
  • 有返回值的方法
#func(run>)
// 一个 > 代表有一个返回值
- (<#type#>)run {
    <#code#>
}
  • 有参数的方法
#func(run::)
// 一个 : 代表有一个参数
- (void)run:(<#type#>)<#param0#> <#name1#>:(<#type#>)<#param1#> {
    <#code#>
}

通用语法功能

  • 批量处理: 以上所有的命令都可以通过后接 *n 进行批量的生成
  • 多命令执行: 你可以通过 + 连续的编写多句命令一块生成

希望大家提出宝贵的意见和建议, 你可以提出 issue 或是发邮件到 caishilin@yahoo.com

End

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生x阅读 15,967评论 3 119
  • 这两天咳嗽,吃嘛都不香。昨晚咳嗽一夜。还好今天在大包里找出来前几月在泰国时候买的那种薄荷润喉片可以对付一下。就是嗓...
    流浪的毛毛阅读 248评论 0 1
  • 秋将尽,露结为霜,冬欲来,情系何方?胸中有困惑,寻师问道在江南。专家名师,会聚稽山之下。先生故里旁,星火相...
    旗叶阅读 729评论 0 0
  • 由于书上的代码用的是Py2.6的,所以当我用Py3.5的时候出现了一些问题。 第2章 k-近邻算法问题1:在我加载...
    瘦长的丰一禾阅读 2,105评论 2 2