Swift3 はこちら
Objective-C にはないもの、break や case などの Objective-C にはなかった機能を持つものなど、予約語を追ってみると面白い知識にたくさん巡り逢えます!
(個人的には indirect が一番好きです!)
文脈による違いなど、調べきれなかった部分もあると思います。もれ、誤り等ございましたら、ご指摘いただけると大変助かります。
また、「こんな機能もある」「こう使うと便利」などもコメントいただけると嬉しいです!
swift tutorial に書いてあるような基礎的なことは簡潔に済ませますのでご了承ください。
よろしくお願いいたします。
class, deinit, enum, extension, func, import, init, inout, internal, let, operator, private, protocol, public, static, struct, subscript, typealias, associatedtype, var, break, case, continue, default, defer, do, else, fallthrough, for, guard, if, in, repeat, return, switch, where, while, as, catch, dynamicType, false, is, nil, rethrows, super, self, Self, throw, throws, true, try, __COLUMN__, #column, __FILE__, #file, __FUNCTION__, #function, __LINE__, #line, _, associativity, convenience, dynamic, didSet, final, get, infix, indirect, lazy, left, mutating, none, nonmutating, optional, override, postfix, precedence, prefix, Protocol, required, right, set, Type, unowned, weak, willSet
宣言 (declarations)
クラス、変数、定数、メソッド、関数などの宣言部分で使用する予約語
class
クラスの宣言や、メソッドやメンバ変数の前に指定することでクラスメソッド、クラス変数の宣言をします。
class のインスタンスは参照型です。
(swift での参照は C 言語のポインタと似たものですが、C 言語のように直接アドレスを指しているのではありません。そのため、 *
は不要です。)
class Sample {
var member = 1
}
let a = Sample()
let b = a
a === b // -> true (指すものは同じ)
a.member = 2
b.member // -> 2
deinit
デストラクタの宣言をします。これは class でのみ有効です。(struct には実装できません)
スーパークラスの deinit はサブクラスの deinit 実行後に自動的に呼ばれます。
class SuperClass {
deinit { print("Super Class's deinit is called") }
}
class SubClass: SuperClass {
deinit { print("Sub Class's deinit is called") }
}
var subClass: SubClass? = SubClass()
subClass = nil
Sub Class's deinit is called
Super Class's deinit is called
enum
列挙体の宣言をします。
extension
定義済みのクラス、構造体、プロトコル、列挙体に対して振る舞いを追加します。
func
メソッドまたは関数の宣言をします。
import
モジュールを読み込みます。
init
コンストラクタを宣言します。
inout
メソッドまたは関数の引数の前に宣言します。
その引数には参照が渡されるようになります。
class SampleClass {}
func inoutSampleForClass(inout sampleClass: SampleClass?) {
sampleClass = nil
}
func withoutInoutSampleForClass(var sampleClass: SampleClass?) {
sampleClass = nil
}
var sampleClass: SampleClass? = SampleClass()
// inout なし
withoutInoutSampleForClass(sampleClass)
sampleClass // => SampleClass のインスタンス
// inout あり
inoutSampleForClass(&sampleClass)
sampleClass // => nil
func inoutSample(inout a: Int) {
a = 100
}
func withoutInoutSample(var a: Int) {
a = 100
}
var varInt = 1
// inout なし
withoutInoutSample(varInt)
varInt // => 1
// inout あり
inoutSample(&varInt)
varInt // => 100
internal
アクセス修飾子の一種です (クラス、変数、定数、メソッド、関数の公開範囲の指定)
同じモジュール(ターゲット)内からアクセスできます。
アクセス修飾子をつけなかった場合、この指定になります。
関連: public, private
let
定数を宣言します。
関連: var
operator
独自の演算子を定義します。
演算子として採用できる文字については規定があります。詳細は iOS Developer Library の Language Reference > Lexical Structure > Operators をご覧ください。
関連: prefix, postfix, infix
prefix operator ☁ {}
prefix func ☁ (inout a: Int) -> Int {
a *= a
return a
}
postfix operator *** {} // 複数文字列も可能
postfix func *** (inout a: Int) -> Int {
a *= a
return a
}
infix operator ☁ {}
func ☁ (left: Int, right: Int) -> Int {
return left + right
}
var hoge = 2
☁hoge // => 4
hoge*** // => 16
1 ☁ 2 // => 3
private
アクセス修飾子の一種です (クラス、変数、定数、メソッド、関数の公開範囲の指定)
同じソースファイル内でのみアクセスできます。
関連: public, internal
protocol
プロトコルを宣言します。
public
アクセス修飾子の一種です (クラス、変数、定数、メソッド、関数の公開範囲の指定)
同じターゲット(モジュール)外からアクセス可能になります。ライブラリなどで API として公開するものに指定します。
関連: private, internal
static
static 変数やstatic メソッドを宣言します。
struct
構造体を宣言します。
subscript
クラスや構造体に [] を実装します。
Objective-C の場合についてはクラスに [], {} を実装するに書いてみました。
class SubscriptSample {
var hoge: AnyObject?
subscript(index: Int) -> String {
get {
return "Int もらいました"
}
set {
hoge = newValue
}
}
subscript(index: String) -> String {
get {
return "String もらいました"
}
// setter なくても良いです
}
subscript(index: AnyObject?) -> String {
return "何かもらいました"
}
}
let subscriptSample = SubscriptSample()
var optionalSample: Int? = 1;
subscriptSample[3] // => "Int もらいました"
subscriptSample["a"] // => "String もらいました"
subscriptSample[nil] // => "何かもらいました"
subscriptSample[optionalSample] // => "何かもらいました"
typealias
- 型の別名を宣言
- [protocol 内で associated type (付属型) の宣言 (Swift2.1まで)](#protocol 内で associated type (付属型) の宣言(Swift2.1まで))
型の別名を宣言
typealias IntAlias = Int
typealias Point = (Int, Int)
protocol 内で associated type (付属型) の宣言(Swift2.1まで)
Swift2.2 からは associatedtype がこの役割となります。この場面での typealias は Swift2.2 から警告、Swift3 から使用不可となります
protocol SampleProtocol {
typealias AssociatedType // 付属型を宣言します
func sampleFunc(param :AssociatedType) -> AssociatedType
}
struct SampleStruct: SampleProtocol {
typealias AssociatedType = Int // 付属型の型を決めます
func sampleFunc(param: AssociatedType) -> AssociatedType {
return param + param
}
}
参考:
The Swift Programming Language (Language Reference -> Declaration -> Type Alias Declaration)
The Swift Programming Language (Language Reference -> Declaration -> Protocol Associated Type Declaration)
associatedtype
(Swift2.2から)
associated type (付属型) の宣言をします。
(Swift2.1までは typealias の役割でした)
protocol SampleProtocol {
associatedtype AssociatedType // 付属型を宣言します
func sampleFunc(param :AssociatedType) -> AssociatedType
}
struct SampleStruct: SampleProtocol {
func sampleFunc(param: Int) -> Int { // 付属型が Int であると決定されます
return param + param
}
}
参考:
The Swift Programming Language (Language Reference -> Declaration -> Type Alias Declaration)
The Swift Programming Language (Language Reference -> Declaration -> Protocol Associated Type Declaration)
var
変数を宣言します。
Keywords used in statements
break
switch 文やループから抜けます。
for, while の前にラベルをつけることで抜けるブロックを指定できます。
詳細: [document の Control Flow -> Labeled Statements] (https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html)
var i = 0
firstLoop: while true {
print("first loop: \(i)")
while true {
print("second loop: \(++i)")
switch i {
case 5:
print("break firstLoop")
break firstLoop
default:
break
}
}
}
print("finish: \(i)")
first loop: 0
second loop: 1
second loop: 2
second loop: 3
second loop: 4
second loop: 5
break firstLoop
finish: 5
関連: continue, fallthrough
###case
列挙子リストの宣言、switch 文内で条件分岐、switch 文内以外で if, for との併用により、パターンマッチングができます。
let optionalSample: Int? = 1;
let optionalArraySample: [Int?] = [1, 2, nil, 3]
if case let x? = optionalSample {
print("optionalSample: \(x)")
}
for case let x? in optionalArraySample {
print("optionalArraySample: \(x)")
}
optionalSample: 1
optionalArraySample: 1
optionalArraySample: 2
optionalArraySample: 3
参考:
Swift 2: Pattern Matching with “if case”,
The Swift Programming Language (Patterns -> Optional Pattern)
関連: enum
###continue
次のループ処理へ移動します。
break と同様にラベルをつけることで移動するループ処理を指定することができます。
var i = 0
firstLoop: while true {
print("first loop: \(i)")
if i != 0 { break }
while true {
print("second loop: \(++i)")
switch i {
case 5:
print("continue firstLoop")
continue firstLoop
default:
break
}
}
}
print("finish: \(i)")
first loop: 0
second loop: 1
second loop: 2
second loop: 3
second loop: 4
second loop: 5
continue firstLoop
first loop: 5
finish: 5
関連: break, fallthrough
###default
switch 文内の条件分岐で、case に当てはまらなかった場合の処理の宣言をします。
関連: switch, case
###defer
スコープを抜ける際に実行する処理を記述します。
func deferSample() {
defer {
print("in defer")
}
print("end of scope")
}
deferSample()
end of scope
in defer
ファイル読み込み処理などに有用とのこと(引用: The defer keyword in Swift 2: try/finally done right)
func deferSample() {
let file = openFile("sample.txt")
defer { closeFile(file) } // 関数から抜ける時に閉じる
// 処理
}
deferSample()
参考:
The Swift Programming Language (Statements -> Defer Statement)
The defer keyword in Swift 2: try/finally done right
###do
スコープを作成します。
catchを繋げることで、スコープ内で発生した例外をcatch文で処理することができます。
関連: catch, try
###else
条件分岐で使用します。
また、guard文では文法上必須となります。
関連: if, guard
###fallthrough
switch 文の中で、次の case 文も評価します。
swift では、break を書かなくてもマッチした case の部分の処理をした後 swich 文を抜けます。
fallthrough を記述しておくとその下の処理も行われます。
let a = 1
switch a {
case 1:
print("1")
fallthrough
case 2:
print("2")
default:
print("default")
}
switch (a) {
case 1:
printf("1\n");
case 2:
printf("2\n");
break;
default:
printf("default\n");
}
1
2
###for
下記の2種類の繰り返し構文を記述できます。
for var i = 0; i < 10; i++ {
// 処理
}
for i in 1...10 {
// 処理
}
for _ in 1...10 {
// 処理
}
###guard
変数または定数が条件に一致するか評価し、一致していない場合、続く else のブロックが実行されます。
このブロックの中では必ず以下のいづれかを使用し、guard が記述されているスコープを抜けなくてはいけません。
func guardSample1(value: Int?) -> String {
guard let value = value where value > 10 else {
// この中では必ずスコープを抜ける処理を書きます
return "in else block"
}
// ここからは value がアンラップされ、また、10 より大きいことが保証されます
return "\(value)"
}
guardSample1(nil) // => in else block
guardSample1(10) // => in else block
guardSample1(100) // => 100
func guardSample2(a: String, b: Int?) -> String {
// 複数の変数・定数の評価もできます
guard let intValue = Int(a), let b = b else {
return "in else block"
}
// ここからは b がアンラップされます
return "\(intValue + b)"
}
guardSample2("a", b: 1) // => in else block
guardSample2("1", b: 1) // => 2
guardSample2("1", b: nil) // => in else block
関連: return, break, continue, throw
###if
続く条件を評価し、一致した(true)場合ブロック内を実行します。
unwrap する場合にも使用します。この構文を Optional binding と言います。詳細はこちら ([Swift] Optional 型についてのまとめ Ver2) に解説されていて分かりやすかったです。
func ifLetSample(value: Int?) {
if let a = value {
value is AnyObject! // => false
a is AnyObject! // => true (a はアンラップされています)
// 処理
}
// 処理
}
###in
文脈によって下記のように意味が変わります。
- クロージャのボディの開始箇所を表します
- for ~ in の形で取り出す要素の配列を指定します
関連: for
###repeat
C言語等の言語における
do {...} while(...)
の do の役割です。
関連: while
###return
返り値を返します。
返り値は下記の 2 パターンです。
- 要素が一つの場合はその要素
- それ以外の場合は tuple
Swift では__@noreturn 属性のメソッド・関数以外は必ず値を返す__という決まりがあります。
そのため、void 関数・メソッドも空の tuple を返します。
func sample() {
return
}
var a = sample() // -> ()
###switch
条件分岐を行います。
switch (1, "a") {
case (1, "b"):
print("1, b")
case (1, _):
print("1, _") // ここがマッチします。 (_ はワイルドカード)
case (1, "a"):
print("1, a") // 上がマッチするので評価されません
}
関連: case
###where
マッチングの条件を追加します。
###while
下記の2種類の繰り返し構文を記述できます。
while condition {
statements
}
repeat {
statements
} while condition
関連: repeat
Keywords used in expressions and types
as
大きく分けて、2 種類の役割があります。
- キャスト
class A {}
let anyObj: AnyObject = A()
let a = anyObj as! A // AnyObject から A にキャスト
- 型を明示すること
let v = 1 as Double
###catch
例外が投げられた際にブロック内が実行されます。
###dynamicType
実行時にインスタンスからメタタイプを取得します。
class SomeBaseClass {
required init() {}
}
class SomeSubClass: SomeBaseClass {
}
let someInstance: SomeBaseClass = SomeSubClass()
let runTimeInstance = someInstance.dynamicType.init()
runTimeInstance is SomeSubClass // -> true
###false
Bool 型の値で偽を表します。
###is
ある型またはあるプロトコルを実装した型として振る舞えるかどうかを検査します。
1 is Int // -> true
(1, 1) is AnyObject // -> false
(1, 1) is (Int, Int) // -> true
// プロトコルの検査
protocol SampleProtocol { }
class SampleClass: SampleProtocol { }
let sampleClassInstance = SampleClass()
sampleClassInstance is SampleClass // true
sampleClassInstance is SampleProtocol // true
###nil
値が空であることを表します。
Optional.None == nil // -> true
###rethrows
引数にとったクロージャが投げた例外をさらに投げます。
func sample(callback: () throws -> Int) rethrows {
try callback()
}
super
親クラスを返します。
self
- インスタンスメソッド内などで単独で使用した場合、インスタンス自身を返します
- [expression (式) に対して呼び出した場合、式が評価された値が返ります](#expression (式) に対して呼び出した場合、式が評価された値が返ります )
- [type (型) に対して呼び出した場合、自身の型が返ります](#type (型) に対して呼び出した場合、自身の型が返ります )
インスタンスメソッド内などで単独で使用した場合、インスタンス自身を返します
class Sample {
var a: Int?
func sampleMethod() -> Sample {
a = 1
return self // 自身 (playground 上では Sample と見えますが、プロパティ a が変更されているので上で作成したインスタンスだと確認できます)
}
}
expression (式) に対して呼び出した場合、式がそのまま返ります
<#expression#>.self
(1 + 1).self
の返り値は (1 + 1)
という式と同等になりそうです。
(1 + 1).self // (1 + 1)
(1 + 1).self // 2 as Int ではない
// 証明
(1 + 1).self + 1.0 // OK
(1 + 1) + 1.0 // OK
let exp = 1 + 1 // 2 as Int
exp + 1.0 // Error (type mismatch)
type (型) に対して呼び出した場合、自身の型が返ります
<#type#>.self
class Sample {
}
Sample.self // -> Sample.Type
Sample.self.init() // -> Sample のインスタンス (= Sample.self は自身の型を返しています)
参考: The Swift Programming Language (Language Reference -> Expressions -> Postfix Self Expression)
###Self
自身の型を返します。
###throw
例外を投げます。
###throws
メソッド、関数の宣言部に書き、例外が投げられる可能性があることを示します。
###true
Bool 型の値で真を表します。
###try
例外が投げられる可能性のある関数・メソッドを実行します。
###__COLUMN__
__COLUMN__ が評価された場所の列番号 (Int)
swift3 から 使用不可
#column
#column が評価された場所の列番号 (Int)
###__FILE__
__FILE__ が評価された場所のファイル名 (String)
swift3 から 使用不可
#file
#file が評価された場所のファイル名 (String)
swift2.2 から使用可能
###__FUNCTION__
__FUNCTION__ が評価された場所の関数・メソッドの名前 (String)
swift3 から 使用不可
#function
#function が評価された場所の関数・メソッドの名前 (String)
swift2.2 から使用可能
###__LINE__
__LINE__ が評価された場所の行番号 (Int)
swift3 から 使用不可
#line
#line が評価された場所の行番号 (Int)
swift2.2 から使用可能
特定の文脈でのみ予約語として使用
associativity
左右に値を取る演算子を宣言した際に、優先度、結合方向を指定します。
指定できる値は下記の 3 種類です。
infix operator <#operator name#> {
precedence <#precedence level#>
associativity <#left | right | none#>
}
infix operator *** {
precedence 100
associativity none
}
infix operator +++ {
precedence 100
associativity none
}
func *** (left: Int, right: Int) -> Int {
return left * right
}
func +++ (left: Int, right: Int) -> Int {
return left + right
}
1 +++ 1 *** 1
/*
error: non-associative operator is adjacent to operator of same precedence
1 +++ 1 *** 1
^
*/
関連: left, right, none, operator, precedence
###convenience
init の前に記述することで、convenience initializer を宣言します。
関連: init
###dynamic
Objective-C のランタイムを使用して値にアクセスします。
dynamic <#var | let #> <# name #>
###didSet
プロパティの値が変更された際の処理を宣言します。
###final
継承を不可にします。
###get
computed property として宣言されたものが呼び出されたときの処理を宣言します。
###infix
左右に被演算子をとる演算子の処理を定義します。
infix operator ☁ {}
func ☁ (left: Int, right: Int) -> Int {
return left + right
}
1 ☁ 2 // => 3
関連: operator
###indirect
列挙体を列挙子の中で再帰的に使えるようになります。
詳細:
indirect を指定すると付加情報を間接指定するようになります。
間接指定しない場合、付加情報のメモリサイズが確定できないため、その列挙体のために確保するメモリサイズも決まりません。
間接指定する場合、付加情報の場所(アドレス)を保持することになるので列挙体のサイズが確定できるようになります。
indirect enum SampleEnum {
case Num(Int)
case IndirectNum(SampleEnum)
}
SampleEnum.IndirectNum(SampleEnum.IndirectNum(SampleEnum.IndirectNum(SampleEnum.Num(1))))
indirect は列挙子の前に書いても良いです。
enum SampleEnum {
case Num(Int)
indirect case IndirectNum(SampleEnum)
}
詳細: Swift Programming Language (Enumerations -> Recursive Enumerations)
###lazy
遅延評価します。
###left
演算子を定義した際に、左結合を指定します。
詳細: このページの associativity 項
関連: associativity, operator, right, none
###mutating
値型のオブジェクトにおいて、自身または自身のプロパティを書き換えるインスタンスメソッドに対して宣言する。
enum SampleEnum {
case A, B, C
case a, b, c
mutating func upperCase() {
switch self {
case .a: self = .A
case .b: self = .B
case .c: self = .C
default: break
}
}
}
struct SampleStruct {
var x = 0
mutating func modifyX(x: Int) {
self.x = x
}
mutating func reset() {
self = SampleStruct()
}
}
###none
演算子を定義した際に、結合方向を指定しません。
詳細: このページの associativity 項
関連: associativity, operator, right, left
###nonmutating
値型のインスタンスメソッドが自身に変更を加えないことを宣言します。
使い所:
computed property 内で定義する set はデフォルトで mutating になります。iOS の API 内では下記のように setter の mutaing を無効にするために使用しています。
var value: Value { get nonmutating set }
###optional
プロトコルの実装を任意に指定します。
###override
親クラスのメソッドやプロパティを上書きする際に宣言します。
###postfix
独自の後置演算子を定義します。
postfix operator *** {}
postfix func *** (inout a: Int) -> Int {
a *= a
return a
}
var hoge = 4
hoge*** // => 16
###precedence
左右に被演算子をとる演算子の優先度 (0 ~ 255) を指定します。
infix operator <#operator name#> {
precedence <#0 ~ 255#>
associativity <#left | right | none#>
}
infix operator *** {
precedence 100
associativity none
}
infix operator +++ {
precedence 200
associativity none
}
func *** (left: Int, right: Int) -> Int {
return left * right
}
func +++ (left: Int, right: Int) -> Int {
return left + right
}
1 +++ 1 *** 0 // => 0
関連: operator, associativity
###prefix
独自の前置演算子を定義します。
prefix operator *** {}
prefix func *** (inout a: Int) -> Int {
a *= a
return a
}
var hoge = 4
***hoge // => 16
###Protocol
Protocol のメタタイプを取得します。
let protocolMetatype: SampleProtocol.Protocol = SampleProtocol.self
関連: Type, dynamicType
###required
サブクラスにイニシャライザのオーバーライドを強制します。
また、サブクラスでそのイニシャライザをオーバーライドする際には override ではなく、required を指定します。
###right
演算子を定義した際に、右結合を指定します。
詳細: このページの associativity 項
関連: associativity, operator, left, none
###set
computed property のセッターを宣言します。
###Type
クラス、構造体、列挙体のメタタイプを取得します。
class Sample {
required init() {}
}
let metatype: Sample.Type = Sample.self
let instance = metatype.init()
関連: Protocol, dynamicType
###unowned
リテインカウントを増やさずに参照を保持します。
weak と違い、参照している値が破棄されないことを前提とします。
nil になった場合は落ちます。
関連: weak
###weak
リテインカウントを増やさずに参照を保持します。
unowned と違い、参照している値が nil になることを許容します。
###willSet
stored property の値への代入が実行される前の処理を宣言します。
関連: didSet
その他
_
ワイルドカード
switch (1, "a") {
case (1, "b"):
print("1, b")
case (1, _):
print("1, _") // ここがマッチします。 (_ はワイルドカード)
}
関連: case
引数名の省略
class Sample {
var a: Int
init(param: Int) {
a = param
}
}
let sample = Sample(param: 1)
class Sample {
var a: Int
init(_ param: Int) {
a = param
}
}
let sample = Sample(1)
値を捨てる
let a: Int
(a, _) = (0, 1)
a // -> 0