はじめに
複数の修飾子のつくプロパティを書いているとき、
「dynamic と public と @objc ってどの順番にすべきなんだっけ?」
とか思っていたら、SwiftLintに参考になるものがあったので、まとめます。
結論(SwiftLintとしての推奨)
-
推奨順序
- [override, acl, setterACL, dynamic, mutators, lazy, final, required, convenience, typeMethods, owned]
-
例
@objc public private(set) dynamic weak var foo: Bar?
public class Foo: Bar {
override public final class var foo: String {
return "bar"
}
}
SwiftLintのルールの参照先
- SwiftLintFramework Reference > modifier_order Reference
- Modifier Order
- ルールの意味
- 修飾子の順番は一貫すべき。
- デフォルトで無効
- ルールの意味
各修飾子の解説
ACL
- Access Control Level のこと
- open
- public
- internal(デフォルト)
- fileprivate
- private
setterACL
- セッターに対応するゲッターよりも__低い__アクセスレベルを指定して、その変数、プロパティ、または添え字の読み取り/書き込みスコープを制限するために使うもの。
- fileprivate(set)
- private(set)
- internal(set) など。
- 例
public struct TrackedString {
public private(set) var numberOfEdits = 0
public var value: String = "" {
didSet {
numberOfEdits += 1
}
}
public init() {}
}
dynamic
- Objective-Cのランタイムを用いるために使う。@objc を使うときにはdynamicキーワードが必要。
- RealmSwiftを使うときには頻出。
mutators
- 多分mutating キーワードのこと。
- Swiftでは、特に要求しない限り、プロパティを変更するメソッドを記述できない。
- メソッドの中でプロパティを変更したいときは、mutating キーワードを使ってマークする必要がある。
- 例
struct Person {
var name: String
mutating func makeAnonymous() {
name = "Anonymous"
}
}
- 呼び出し方
var person = Person(name: "Ed")
person.makeAnonymous()
lazy
- 参照された時に初めて初期値が設定されるプロパティ。
- 不要なメモリの消費やパフォーマンスの低下を防ぐことができる。
- ただ、もし使うときは気を付ける。いくつか記事見ていると、安易に使うと不具合の元な感じが伝わってきた。
便利なlazyですが、
初期化タイミングが不明瞭なため思わぬバグを引き起こすことがあります。私見ではありますが、
プロジェクト内での利用タイミングの統一やコメントでの補足等しておく必要はあるかと思います。
lazyなプロパティは
不要なメモリの消費やパフォーマンスの低下を防ぐことができますが
使い方を誤ると
わかりづらい不具合を混ぜてしまう可能性があることがわかりました。
final
-
override を防ぐ。
-
メソッド、プロパティ、subscript(添え字?)が override されることを防ぐ。
- final var
- final func
- final class func
- final subscript
-
クラスが継承されることを防ぐ。サブクラス化しようとすると、コンパイル時エラーになる。
- final class
required
- クラスの初期化子の前につけて、クラスの全てのサブクラスがその初期化子を実装する必要があることを示す。
- 例
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initializer goes here
}
}
convenience
- クラスの初期化子をサポートする。指定した初期化子を呼び出し、その初期化子のパラメーターの一部をデフォルト値に設定できる。
- 例
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
typemethod
- 例
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
owned
- unowned
- weak
参考サイト
- Swift Document