v1.0.0
このコーディング規約は以下を方針として策定しています。
- 一貫性
- 可読性
- 冗長性の排除
キャメルケースとし、先頭を大文字とすること。
(UpperCamelCase)
理由
API Design Guidelinesに従う。
例
良い例
class SomeClass<T> {
...
}
enum SomeEnum {
...
}
struct SomeStruct {
typealias Element = String
...
}
protocol SomeProtocol {
associatedtype Parameter
...
}悪い例
class someClass<t> {
...
}
enum someEnum {
...
}
struct someStruct {
typealias element = String
...
}
protocol someProtocol {
associatedtype parameter
...
}キャメルケースとし、先頭は小文字とすること。
(lowerCamelCase)
理由
API Design Guidelinesに従う。
例
良い例
struct SomeStruct {
let someNumberProperty: Int
func someMethod() -> String {
...
}
}
enum SomeEnum {
case red
case green
case blue
...
}悪い例
struct SomeStruct {
let SomeNumberProperty: Int
func SomeMethod() -> String {
...
}
}
enum SomeEnum {
case Red
case Green
case Blue
...
}コード内の固定値等に使用するグローバル定数名を他の変数やプロパティ値等と区別するため、先頭に'k'をつける。 ※ドイツ語で定数を意味するKonstantの頭文字
良い例
let kCellHeight = 40悪い例
let cellHeight = 40クラス名にプレフィックスは付けない。
理由
Swiftでは名前空間が存在するためクラス名は衝突せず、ただ可読性を下げてしまうため。
また、Swift3でFoundationAPIsのNSプレフィックスは除去されるため。
例
良い例
class SomeClass {
...
}悪い例
class SDTSomeClass {
...
}Protocol名はSwiftの標準ライブラリに合わせるようにします。 状態を表すときは語尾にTypeを付けて、状態が変位可能な場合や、ある挙動を実行可能な場合は語尾にableを付けます。
- public protocol IntegerType
- public protocol CustomStringConvertible
- public protocol Equatable
すべて大文字またはすべて小文字とすること。
理由
API Design Guidelinesに従う。
例
let url: NSURL = ...
let thumbnailURL: NSURL = ...
let id: String = ...
let userID: String = ...NSURLの場合○○URLを使い、Stringであれば○○URLStringとする。
同様にNSDateの場合○○Dateを使い、Stringであれば○○DateStringとする。
理由
混同しやすいため。
例
良い例
var thumbnailURL: URL
var imageURLString: String
var lastUpdateDate: Date
var birthdayString: String悪い例
var thumbnailURL: String
var lastUpdateDate: Stringextensionのみのファイル名はUIView+○○(機能名).swiftとすること。
加えて、extensionは機能単位でグルーピングすること。
理由
extensionであることを明確にするため。
機能ごとにextensionを作り、可読性をあげるため。
良い例
UIView+Border.swift
extension UIView {
@IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
@IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
@IBInspectable
var borderColor: UIColor? {
get {
return layer.borderColor.map { UIColor(CGColor: $0) }
}
set {
layer.borderColor = newValue?.CGColor
}
}
}悪い例
Border.swift
extension UIView {
@IBInspectable
var borderColor: UIColor? {
get {
return layer.borderColor.map { UIColor(CGColor: $0) }
}
set {
layer.borderColor = newValue?.CGColor
}
}
// ↓↓関係ない
var hasSubview: Bool {
return !subviews.isEmpty
}
}その他命名に関しては、API Design Guidelinesを参考にすること。
以下はFundamentalsからの引用です。
・利用の観点から、明確さが最大の目標である。
メソッドやプロパティなどのエンティティは、一度だけ定義され、何度も使われるものである。
これらを利用する際、明確かつ簡潔であるようにAPIを設計しなければならない。
APIの評価をする際は、定義を読むだけでは不十分である。
コンテキスト上で明確であるよう、APIを使っている例も含めて評価しなければならない。
・明確さは簡潔さよりも重要である。
Swiftのコードは短く書くことができるが、できるだけ少ない文字数で
可能な限り最小のコードを実現することが目標ではない。
Swiftにおける簡潔さは
強力な型システムと自然にボイラープレートコードを減らすことができる性質から生まれた、
副次的なものである。
・すべての宣言にドキュメントとしてコメントを記載すること。
ドキュメントを書くことで得られる洞察は設計上に大きな影響をあたえるので、
端折らないこと。
以下の順に書くこと。
extensionを使い、関連メソッドをグルーピングするのは任意とする。
// 1.import
import UIKit
// 2.protocol
protocol ViewControllerDelegate {
}
// 3.class・struct・enum
final class ViewController: UIViewController {
// 4.typealias
// 5.Inner class, enum & struct
// 6.static member
//
// 6-1.property
// |
// | 6-1-1.public
// | |
// | | 6-1-1-1.let
// | | 6-1-1-2.var
// | | 6-1-1-3.computed var
// |
// | 6-1-2.internal
// | |
// | | 6-1-2-1.let
// | | 6-1-2-2.var
// | | 6-1-2-3.computed var
// |
// | 6-1-3.private
// | |
// | | 6-1-3-1.let
// | | 6-1-3-2.var
// | | 6-1-3-3.computed var
//
// 6-2.method
// |
// | 6-2-1.public
// |
// | 6-2-2.internal
// |
// | 6-2-3.private
// 7.instance member
//
// 7-1.property
// |
// | 7-1-1.public
// | |
// | | 7-1-1-1.@~
// | | 7-1-1-2.let
// | | 7-1-1-3.var
// | | 7-1-1-4.computed var
// |
// | 7-1-2.internal
// | |
// | | 7-1-2-1.@~
// | | 7-1-2-2.let
// | | 7-1-2-3.var
// | | 7-1-2-4.computed var
// |
// | 7-1-3.private
// | |
// | | 7-1-3-1.@~
// | | 7-1-3-2.let
// | | 7-1-3-3.var
// | | 7-1-3-4.computed var
//
// 7-2.method
// |
// | 7-2-1.public
// | |
// | | 7-2-1-1.init
// | | 7-2-1-2.life cycle
// | | 7-2-1-3.@~
// | | 7-2-1-4.others
// |
// | 7-2-2.internal
// | |
// | | 7-2-2-1.init
// | | 7-2-2-2.life cycle
// | | 7-2-2-3.@~
// | | 7-2-2-4.others
// |
// | 7-2-3.private
// | |
// | | 7-2-2-1.init
// | | 7-2-2-2.life cycle
// | | 7-2-2-3.@~
// | | 7-2-2-4.others
}
// 8.extension
extension ViewController: UITableViewDelegate {
}理由
書く順序を統一することで、参照したい情報へのアクセスを効率的にする。
以下の順に書くこと。
@~
↓
アクセス制御
↓
static, class
↓
dynamic, lazy, weak
↓
let, var
理由
統一のため。
以下の順に書くこと。
フレームワーク
↓
ライブラリ
また、同系列内ではアルファベット順に書くこと。
理由
コンフリクトを防止するため。
順序を揃えることで可読性を上げるため。
- 使われていないコード
- スーパークラスを呼び出すだけのコード
- Xcodeのテンプレートとして書かれたままのコード
は削除する。
理由
無用なコードは可読性を下げるため。
- ブラケットの前後には半角スペースを1つおくこと。
- メソッドの戻り値の->の前後に半角スペースを1つおくこと。
- コロンの前はスペースを入れず、コロンの後ろに1つスペースをいれること。(三項演算子を除く)
- カンマの前にはスペースを入れず、カンマの後ろに1つスペースをいれること。
- 演算子の実装の際は演算子の後ろに1つスペースをおくこと。
理由
一貫性を持たせるため。
例
良い例
func something() -> Int {
let some: Int = 0
}
func <| (lhs: Int, rhs: Int) -> Int
func <|< <A>(lhs: A, rhs: A) -> A悪い例
func something()->Int{
let some :Int = 0
}
func <|(lhs: Int , rhs: Int)->Int
func <|<<A>(lhs: A,rhs: A)->Aひとつのextensionで実装するプロトコルは1つとする。
また、継承とプロトコルの準拠を同時に行わないこと。
理由
関連メソッドをグルーピングすることで可読性を上げるため。
例
良い例
class ViewController: UIViewController {
...
}
extension ViewController: UITableViewDataSource {
...
}
extension ViewController: UITableViewDelegate {
...
}悪い例
class ViewController: UIViewController, UITableViewDataSource {
...
}extension ViewController: UITableViewDataSource, UITableViewDelegate {
...
}広く使われるものであれば独立したファイルに宣言すること。
ある構造に特有のものであればその構造内で宣言すること。
理由
enumのある場所を統一するため。
エディター上で折り返したら改行すること。
また、改行をいれたらすべての引数の前で改行すること。
理由
可読性を上げるため。
行末のセミコロンの使用を禁止する。
理由
必要ないため。
条件文を()で囲わないこと。
理由
必要ないため。
例
良い例
if names.isEmpty {
...
}悪い例
if (names.isEmpty) {
...
}未対応の機能には以下を記述すること。
// TODO: 〜修正が必要な場合は以下を記述すること。
// FIXME: 〜理由
実装漏れを防止するため。
アクセス制御は可能な限りprivateを指定すること。
理由
そのクラス内、メソッド内…ということが担保でき、実装変更時の影響範囲を小さくできるため。
継承、オーバーライドをさせたくない場合は明示的にfinalを宣言すること。
理由
継承、オーバーライド不可なことを明示的に示すことで設計意図を示せるため。
また、副次的にパフォーマンス向上にも繋がるため。
必要な時にのみ使用すること。
(引数と同じ名前のプロパティ、クロージャ内等)
理由
統一し、また冗長性を排除するため。
例
良い例
struct Person {
let name: String
init(name: String) {
self.name = name
}
func printName() {
print(name)
}
let callback: () -> String = {
return self.name
}
}悪い例
struct Person {
let name: String
func printName() {
print(self.name)
}
}算出型プロパティにおいて、ゲッターのみ定義する場合はgetのクロージャを省略すること。
理由
不要なため。
例
良い例
class Person {
let first: String
let family: String
var full: String = {
return first + family
}
}悪い例
class Person {
let first: String
let family: String
var full: String = {
get {
return first + family
}
}
}var宣言を使用するのは、その値が変わり得る等、明確な理由があるときのみとする。
それ以外の場合はlet宣言を使用する。
理由
より安全なコードにするため。
意図しない値の変更を防ぐため。
letを使用することでプログラマーが値が変わらないことを確認することができる。
逆に、varによって宣言された変数が変更されることを予期できる。
最大限利用すること。
理由
冗長性を排除し、シンプルなコードにするため。
例
良い例
let name = "KentaKudo"悪い例
let name: String = "KentaKudo"空配列・空辞書の初期化の際は、型推論を利用した形で書くこと。
理由
統一のため。
例
良い例
var names = [String]()
var jsonDic = [String: AnyObject]()悪い例
var names: [String] = []
var jsonDic: [String: AnyObject] = [:]糖衣構文がある場合はそちらを使用すること。
Voidに関しては、可読性を理由に例外を認める。
理由
統一のため。
例
良い例
var names: [String]
var jsonDic: [String: AnyObject]
var title: String?
var someClosure: () -> ()悪い例
var names: Array<String>
var jsonDic: Dictionary<String, AnyObject>
var title: Optional<String>
var someClosure: Void -> Void文字列はNSString型でなく、String型を使用すること。
また、文字列長判定にはcharacters.countを使用すること。
NSNumber、NSArray、NSDictionary型も同様に、
Swiftネイティブな型を利用すること。
理由
swiftの型で統一するため。
guard文を利用し、例外の場合に早めに制御を返すこと。
理由
guardにより制御が返ることを明示し、可読性を上げるため。
また、ネストを減らすことで書きやすさ読みやすさを上げるため。
例
良い例
guard hogehoge else {
return
}悪い例
if hogehoge {
} else {
return
}利用をIBOutletに限定する。
理由
nilアクセスの可能性をできるだけ下げるため。
!(forced unwrap)を使わず、optional chaining, optional binding, nil coalescingを使用すること。
また、optional bindingの際には、同じ変数名で変数宣言すること。
理由
nilアクセスの可能性をできるだけ下げるため。
アンラップ前の変数を使ってしまうバグを防ぐため。
例
良い例
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let navigationItem = navigationController?.navigationItem
}
}let response: AnyObject = [:]
if let json = response as? [String: AnyObject] {
...
}let someNumber: Int? = 10
let otherNumber: Int = someNumber ?? 0if let some = some {
...
}悪い例
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let navigationItem = navigationController!.navigationItem
}
}let response: AnyObject = [:]
let json = response as! [String: AnyObject]let someNumber: Int? = 10
let otherNumber: Int = someNumber!if let bindedSome = some {
...
}弱参照をする際にはunownedではなくweakを使用すること。
理由
nilアクセスの可能性をできるだけ下げるため。
例
良い例
someFunc { [weak self] in
...
}悪い例
someFunc { [unowned self] in
...
}catchで例外を処理しない場合はtry!ではなく、try?を使用する。
理由
nilアクセスの可能性をできるだけ下げるため。
例
良い例
let someInt = try? someErrorThrowMethod() ?? 0悪い例
let someInt = try! someErrorThrowMethod()一行で記述する場合に限り、引数名を省略すること。
メソッドが複数のクロージャを引数にとる場合、trailingクロージャの省略形を使用しないこと。
理由
複数行のクロージャ内で引数名を省略した場合に可読性が落ちるため。
複数のクロージャを引数にするメソッドの呼び出しでtrailingクロージャの省略形を使うと、外部引数名が省略され、可読性が落ちるため。
例
良い例
let someClosure: String -> Int? = { Int($0) }
let someClosure: String -> Int? = { string in
let intValue = Int(string)
return intValue
}
UIView.animateWithDuration(10.0,
animations: {
print("animate")
},
completion: { _ in
print("completed")
})悪い例
let someClosure: String -> Int? = {
let intValue = Int($0)
return intValue
}
UIView.animateWithDuration(10.0,
animations: {
print("animate")
}) { _ in
print("competed")
}warningを可能な限り解消すること。
却下理由
Xcodeに関する事項であり、コーディングの規約としては不適切と判断した。
第一引数について、必要な場合は外部引数名を使うこと。
却下理由
swift3では第一引数にデフォルトで外部引数名がつくため。
備考
swift3に移行後は項目を削除する。
関数型の使用を制限する。
却下理由
プロジェクトごとに判断されるべきものであり、コーディング規約としては不適切と判断した。
AutoLayoutを使用する際に関する規約。
却下理由
各プロジェクトに裁量を任せることとし、コーディング規約の対象外とした。