Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
311 lines (216 sloc) 11.5 KB

Swift コーディング規約

このドキュメントは、以下に挙げる目標を達成できる方法を促進するための試みとして作成されたものです。(大まかな優先度順となっています)

  1. より厳密で、プログラマが誤解する可能性が少ないこと
  2. 意図が明確であること
  3. 冗長さが排除されていること
  4. 美学についての議論が少ないこと

もし提案があれば、ガイドラインを読み、プルリクエストを送ってください。⚡️

また、日本語版のこのドキュメントでは Swift 言語仕様翻訳において詳解Swiftを参考としています。


空白

  • スペースではなく、タブを使う
  • ファイル終端は改行する
  • コードをロジック毎に分割するために、空白行を惜しみなく使う
  • 行末に空白を残さない
    • 空白行でのインデント調整もしない

可能な限りvar宣言よりもlet宣言を使う

可能な限り(どちらか迷った時にも)var foo = …よりlet foo = …を使いましょう。varは本当に使わないといけない時にだけ使うようにしましょう。(具体的には、あなたがその値が変わり得ることを知っているときや、weakプロパティ修飾子を使っている時などです)

理由: 二つのキーワードの意図と意味は明瞭ですが、デフォルトでletを使うことは、より安全でより明確なコードになります。

let宣言は、その変数の値が変わらないことを保証すると同時に、それをプログラマに明確に伝えます。そのため、その後に続くコードにおいて、その変数の用途を推測しやすくなります。

コードを論理的に理解するのがより簡単になります。値が決して変わらないと考えているにもかかわらずvarを使うと、本当に値が変わらないかどうかを手動でチェックしなければいけません。

この方法に従うと結果的に、var宣言が使われているのを発見した時は必ず、その値が変わり得ると推測したり、その理由を考えることができます。

Return と break を早期に行う

実行を継続するには基準を満たす必要があるような場合は、なるべく早期にコードブロックから抜け出すようにしましょう。

その際、以下のようにする代わりに:

if n.isNumber {
    // Use n here
} else {
    return
}

以下のように書きましょう:

guard n.isNumber else {
    return
}
// Use n here

If文でも同じことが可能ですが、guardを使うことが推奨されます。guard文ではreturnbreakcontinueが無いとコンパイルエラーとなるため、コードブロックから抜け出すことが保証されるからです。

オプショナル型の開示指定は避ける

FooType?もしくはFooType!型の変数fooがある場合、そこにあるfoo!を得ようとしてfooに対して開示指定を行うのは可能な限り避けないといけません。

代わりに、以下のようにしましょう:

if let foo = foo {
    // 開示された`foo`の値を使う
} else {
    // 必要であれば、ここでオプショナルがnilの場合の処理を行う
}

他の方法として、Swift のオプショナルチェーンを以下のように使った方が良い場合もあります。

// `foo`がnilでない場合は関数を呼ぶ、`foo`がnilの場合は関数呼び出し自体を無視する
foo?.callSomethingIfFooIsNotNil()

理由: 明示的な if letによるオプショナル束縛構文は、結果的に安全なコードとなるからです。 開示指定はランタイムでのクラッシュを生み出してしまう可能性があります。

暗黙的開示オプショナル型の使用を避ける

もしfooがnilになる場合がある場合、可能な限りlet foo: FooType!ではなくlet foo: FooType?を使うべきです。(一般に、!の代わりに?を使うことができると覚えておきましょう)

理由: 明示的なオプショナル型は安全なコードを生み出すからです。暗黙的開示オプショナル型はランタイム時のクラッシュを生み出す可能性を持っています。

読み取り専用のプロパティと添字付けのgetterは暗黙的にする

可能な限り、読み取り専用のプロパティと添字付けではgetキーワードを省きましょう。

以下のように書きましょう:

var myGreatProperty: Int {
	return 4
}

subscript(index: Int) -> T {
    return objects[index]
}

… 以下は避けましょう:

var myGreatProperty: Int {
	get {
		return 4
	}
}

subscript(index: Int) -> T {
    get {
        return objects[index]
    }
}

理由: 一つ目の方が意図と意味が明確だからです。またコードも少なく済みます。

トップレベルの定義には常にアクセス制御を明記する

トップレベルの関数、型、変数には、常にアクセス制御指定子を明記するべきです。

public var whoopsGlobalState: Int
internal struct TheFez {}
private func doTheThings(things: [Thing]) {}

しかし、トップレベルより下の定義については、必要に応じてアクセス制御を暗黙的にできます。

internal struct TheFez {
	var owner: Person = Joshaber()
}

理由: トップレベルの定義がinternalであることが適切である場合は滅多にないでしょう。そして、アクセス制御が明記されていることによって、深く考えた結果そのようにしたということが明らかになります。定義において、同じアクセス制御を繰り返すことはただ冗長なだけなので、デフォルト値が通常合理的です。

型の指定では、常にコロンを識別子の後ろに繋げる

識別子に型を指定する時は、常に識別子のすぐ後ろにコロンを置き、空白を一つあけて型名を書きましょう。

class SmallBatchSustainableFairtrade: Coffee { ... }

let timeToCoffee: NSTimeInterval = 2

func makeCoffee(type: CoffeeType) -> Coffee { ... }

理由: 型指定子は、_識別子_に対してなんらかの意味づけをしようとしているので、識別子の近くに定義するべきです。

同じように、ディクショナリの型定義をするときも、常にキーの型のすぐ後にコロンをおいて、空白の後に値の型を指定します。

let capitals: [Country: City] = [ Sweden: Stockholm ]

明示的なself参照は必要な時だけ

selfの持つプロパティやメソッドへアクセスする時、デフォルトではselfへの参照は省きましょう。

private class History {
	var events: [Event]

	func rewrite() {
		events = []
	}
}

明示的にselfを入れるのは言語によって必要と判断された場合だけにしましょう-たとえばクロージャ内、もしくはパラメータ名の衝突がある場合などです。

extension History {
	init(events: [Event]) {
		self.events = events
	}

	var whenVictorious: () -> () {
		return {
			self.rewrite()
		}
	}
}

理由: これによってクロージャにおけるselfのキャプチャリングが目立つようになります。そしてその他の場所における冗長さが無くなります。

クラスより構造体を使うようにする

クラスでしか提供できない機能(同一性やデイニシャライザなど)を必要としない限り、クラスではなく構造体で実装しましょう。

継承は通常、クラスを使う主な良い理由には_なりません_。なぜなら、多様性はプロトコルによって実現可能であり、実装の再利用はコンポジションによって実現可能であるからです。

例として以下のクラス構造をあげます。

class Vehicle {
    let numberOfWheels: Int

    init(numberOfWheels: Int) {
        self.numberOfWheels = numberOfWheels
    }

    func maximumTotalTirePressure(pressurePerWheel: Float) -> Float {
        return pressurePerWheel * Float(numberOfWheels)
    }
}

class Bicycle: Vehicle {
    init() {
        super.init(numberOfWheels: 2)
    }
}

class Car: Vehicle {
    init() {
        super.init(numberOfWheels: 4)
    }
}

上記は以下のようにプロトコルと構造体で書き換えられます。

protocol Vehicle {
    var numberOfWheels: Int { get }
}

func maximumTotalTirePressure(vehicle: Vehicle, pressurePerWheel: Float) -> Float {
    return pressurePerWheel * Float(vehicle.numberOfWheels)
}

struct Bicycle: Vehicle {
    let numberOfWheels = 2
}

struct Car: Vehicle {
    let numberOfWheels = 4
}

理由: 値型はシンプルで説明しやすく、letキーワードの挙動通りに動作してくれるからです。

デフォルトでクラスをfinalにする

クラスは初めはfinalにしておき、継承の正当な必要性が確認された場合にサブクラス化を許容する目的でのみ変更するべきです。さらにその場合、クラス内のそれぞれのクラスも、可能な限り同じルールに則り、同じようにfinalを適用します。

理由: 一般的に、継承よりもコンポジションを使うことが望ましいので、継承を選択しようとするときにその決定についてよく考える余地があることを示すことができるかもしれません。

可能な限り型パラメータは省く

パラメータ化された型のメソッドは、引数の型がレシーバの型と同一の場合は型パラメータを省くことができます。たとえば:

struct Composite<T> {
	
	func compose(other: Composite<T>) -> Composite<T> {
		return Composite<T>(self, other)
	}
}

上記は以下のように書くことができます:

struct Composite<T> {
	
	func compose(other: Composite) -> Composite {
		return Composite(self, other)
	}
}

理由: 冗長な型パラメータを省くことで意図が明確になり、その一方で、返り値の型が違う型パラメータを取る場合を明確に示すことができるからです。

オペレータ定義では空白を使う

オペレータを定義するときは、オペレータの前後に空白を使いましょう。
以下のようではなく:

func <|(lhs: Int, rhs: Int) -> Int
func <|<<A>(lhs: A, rhs: A) -> A

以下のように書きましょう:

func <| (lhs: Int, rhs: Int) -> Int
func <|< <A>(lhs: A, rhs: A) -> A

理由: オペレータは記号でできており、それらが型や値のパラメータのリストに使われる記号とくっついていると読みにくくなるからです。 空白を入れることでそれらをより明確に分けることができます。

翻訳