blog

iOS開発ツール - コード生成、重複ソートコードのコピー

FlyCodingはAppleのプラグイン機構を使って書かれたXcodeプラグインで、最新のXcode上で動作し、フロントエンドでEmmetに似た機能を提供します。Emmetのようなフロントエンドの機...

May 10, 2020 · 13 min. read
シェア

FlyCoding - Emmet for Xcode

コンパイルには Swift 5 を使用してください。

FlyCodingは、Appleが提供するプラグイン機構を使って書かれたXcodeプラグインで、最新のXcode上で動作し、フロントエンドで Emmetと 同様の機能を提供します。 Swfit/Objective-Cの コードを特別な構文を使って素早く生成することができます。 UIコントロールや制約を繰り返し書くのはとても面倒で機械的な作業ですが、避けては通れないものです。FlyCodingは、プロパティ、メソッド、制約を素早く生成するのに役立ちます。 FlyCodingはまだ最初のバージョンをリリースしたばかりで、より多くの機能はまだ構想中です。

現在の開発進捗状況:
  • バージョン2.0の新機能は、シェルのようなコマンドでテキストを操作する強力な@doコマンドです。
    • remove
    • to
    • copy
    • move
    • sort
  • Objective-C / Swift 属性生成
  • Objective-C / Swiftビューの迅速な作成
  • Masonry / SnapKit 制約の生成
  • SwiftでのシステムネイティブなAutoLayout制約
  • クイック生成方法
  • バッチ処理には「* N」を使用します。

Snipkitレイアウトのコード例を生成

@do

@do move 10 34 to 44
// 10行目から34行目までを44行目に移動する。
//
//コマンドはとても使いやすく、どこにでも書くことができる。
//  @do 先頭で、次のコマンドを実行する。
//ここでmoveは移動コマンドで、次のハンガー10が開始行、34が終了行である。
//to は、コンテンツを指定された場所に移動させるコマンドでもある。
//to moveコマンドの組み合わせではなく、独立したコマンドである。詳細はtoコマンドで紹介する。
//次のパラメーターはtoコマンドである

理論的には、無制限の数のコマンドをブリッジすることが可能で、各コマンドは独立した処理単位であり、それが完了したときに共通のコンテキストを介して状態を渡します。

コマンド削除

  • 削除
    • rm 10 .
    • arg1 [arg2]
      • arg1 開始行数を示します。
      • arg2は終了行数を示し、このパラメータは空でもかまいません。
      • 行を表すのに数字を使うだけでなく、. を使うこともできます。

移動コマンド

  • move/mv
    • @do mv 10 . to 30
    • arg1 [arg2]* arg1 は開始行数を表します * arg2 は終了行数を表します、このパラメータはnullでもかまいません。 で現在の行を表すこともできます。
    • to arg1* 指定された場所に移動するにはtoコマンドが必要 * arg1は移動する行を示します。

コマンドのコピー

  • コピー/cp
    • @do cp 10 . to 30
    • arg1 [arg2]* arg1 は開始行番号を表します * arg2 は終了行番号を表します、このパラメータは空でもかまいません。 を使うこともできます。
    • to arg1* 指定された場所に移動するにはtoコマンドが必要 * arg1は移動する行を示します。

コマンド削除

各行の長さに従って、範囲内のコードを降順に並べます。

  • ソート
    • 10 .
    • arg1 [arg2]
      • arg1は開始行、arg2が空の場合は終了行がコマンドの現在行、開始行はコマンドの現在行からarg1を引いた行を意味します。
      • arg1 が終了行を示す場合、arg2 は終了行数を示します。
      • 行を表すのに数字を使うだけでなく、arg2は. で現在の行を表すこともできます。

属性生成

移動コマンド

  • 個々のプロパティ
pv.UIImageView
// pv はアトリビュート・コントロール、pはプライベート、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は公開、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とマークされる。 u/unowned、 c/class   s/static
weak var <#name#>: EatProtocol?
  • プロパティの一括生成
pl.UILabel{} *2
// *2 間にスペースを入れない。通常、データモデルやUIを書くときに使う。
private let <#name#> = UILabel()
private let <#name#> = UILabel()
  • ブロック初期化値の生成
plb.UIButton
// 記号bはブロックを意味する。
private let <#name#>: UIButton = {
 <#code#>
}()

ヒント: 属性にタグが付けられていない場合、自動的に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 ブロックでは、属性のブロック初期化値を生成します。
F 自己完結的で、属性の初期値は config 関数によって提供されます。

Objective-C

Objective-Cで使われる構文は、キーワードと生成されるルック&フィールを除けば、Swiftとあまり変わりません。

  • 個々のプロパティ
.UIImageView *
// デフォルトの説明は nonatomic, strong
@property (nonatomic, strong) UIImageView *<#name#>
  • フルプロパティの生成
c.NSString *name;
// もし ' ; ' 迅速なコーディングのために、クラスが属性名と連結されていることを示す。
@property (nonatomic, copy) NSString *name;

ヒント: class はクラス属性をマークするために使用できます。

Objective-C 属性タグ早見表

s static
w weak
a assign
r readonly
g getter=<#getterName#>
c class
n nullable
N nonnull
c class

制約コードの生成

Objective-CではMasonryを、SwiftではSnapKitを使用しています。

スナップキット

  • レイアウトの追加
 #snpm(iconView, e=self)
 // snpm これはmakeConstraintsで、()内のステートメントを記号で分割する方法である
 // 最初のパラメータは制約を追加するオブジェクトで、残りはレイアウト文である。
 // 各ステートメントは3つの部分に分かれており、左の部分が制約オブジェクトのプロパティ、中央の部分が制約メソッド、右の部分が制約メソッド、左の部分が制約オブジェクトのプロパティである。
 // 右辺は、制約または他の制約オブジェクトの値である。
 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 Let
t top
b
r
w weak
h height
x centerX
y centerY
c class
s static
e edges
--- 制約レベル
r readonly
h height
m .medium
l Let
--- パラメータの比較
>= greaterThanOrEqualTo
<= lessThanOrEqualTo
= equalTo
--- 算術記号
- Offset(-value)
+ Offset(value)
* multipliedBy(value)
/ dividedBy(value)

石工

主な使い方はSnapKitと同じですが、主な違いは以下の通りです。

  • 作成、更新、リセット
@masm(iconView, e=self) //  
@masu(iconView, e=self) //  
@masrm(iconView, e=self) //  

Tips:OCのコマンドの接頭辞として@を使うことができます。これは主に、#が自動的にOCファイルの最初のカラムになり、コードの構造に影響するからです。

  • 制約の中にRはもうありません。
  • 新しい== / >== / <== 比較では、主にmas_の前に=が1つ少ないバージョンと比較。
@masm(iconView, e=self) //  
@masu(iconView, e=self) //  
@masrm(iconView, e=self) //  

Swift

主な使い方はSnapKit/Masonryと同じですが、主な違いは以下のとおりです。

  • ステートメントを実行するには#layoutを使用します。
  • s(サイズ) / c(センター) / e(エッジ)のサポートは削除されましたが、将来のアップデートで再度追加される予定です。
  • 制約条件における除算の操作が使えなくなることを削除
  • オフセット制御のために単に+`-を使用する代わりに、一定の制約やオフセットを設定したい場合は、:001形式を使用します。
@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];

作成方法

スウィフト

  • メソッドの作成

#funcは#fという略語を使うことができます。

#func(eat)
// シンプルなメソッドを生成する
func eat() {
 <#code#>
}
  • パーミッションの設定方法
#func(@p.run)
// タグは属性と同じである。
@objc private func run() {
 <#code#>
}
  • パラメタ化メソッド
#func(run::)
// One: パラメーターが1つであることを意味する。
func run(<#name#>: <#type#>, <#name#>: <#type#>) {
 <#code#>
}
  • 戻り値を持つメソッド
#func(run>)
//   > は戻り値があることを意味する
func run() -> <#return#> {
 <#code#>
}
// 複数の戻り値はタプルを返す
#func(run>>)
func run() -> (<#return#>, <#return#>) {
 <#code#>
}

オブジェクティブC

  • メソッドの作成
#func(run)
// シンプルなメソッドを生成する
- (void)run {
 <#code#>
}
  • 戻り値を持つメソッド
#func(run>)
//   > は戻り値があることを意味する
- (<#type#>)run {
 <#code#>
}
  • パラメタ化メソッド
#func(run::)
// One: パラメーターが1つであることを意味する。
- (void)run:(<#type#>)<#param0#> <#name1#>:(<#type#>)<#param1#> {
 <#code#>
}

一般的な構文関数

  • バッチ処理: 上記のすべてのコマンドは、接尾辞に*nを 付けることでバッチ処理することができます
  • 作成方法

ご意見、ご感想は、caishilin@yahoo.com までお寄せください。

#終了

Read next

つの`dateオブジェクト`が同じ日であるかどうかを判定する方法

渡された2つの日付オブジェクトが同じ日であるかどうかを判定します。 () を使って、渡された Date オブジェクトを全体的に比較します。 このメソッドは、ISO標準を使用してDateオブジェクトを文字列に変換します。 この標準はISO-8601と呼ばれ、フォーマットは次のとおりです:YYYY...

May 10, 2020 · 2 min read