82
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SwiftAdvent Calendar 2021

Day 1

Swift5 全予約語 (109語) の解説

Last updated at Posted at 2021-12-01

ドキュメントから漏れている予約語もあるため、下記情報を統合してカウントしています。

宣言 (declarations)

型、変数、定数、メソッド、関数などの宣言部分で使用する予約語

actor

[Swift 5.5~]
Swift の型の種類の一つである Actor 型を宣言します。

actor SampleActor {
    var mutableValue = "mutable"
    let constValue = "const"
    
    func defaultFunc() {}

    nonisolated func nonisolatedFunc() {}
    nonisolated var nonisolatedComputedProperty: String {
        "computedProperty getter"
    }
}

Actor を使うことで、複数スレッドからの変更可能データに対する同時アクセスによって発生するデータの破損(data race)を防ぐコードをコンパイラのサポートを受けながら書けるようになります。
Actor の概要は Swift LanguageGuide > Concurrency > Actors に記載されています。実際のアプリ開発での使い所のイメージを掴んでみたい場合は WWDC21 Swift concurrency: Update a sample app が分かりやすくてオススメです。

詳細

Actor の特徴は並列処理の実行環境下でのデータの保護です。(より厳密に言うなら、actor の instance を通すことで、隔離された状態に同期的にアクセスする機能を提供するものです。)
Actor の持つ変更可能なデータや method に対して同時に複数のタスクからアクセスされないように自動的に制御されます。他のタスクからアクセスされている場合はアクセス可能になるまで待機します。そのため、アクセスする場所では await でマークしておく必要があります。

await sampleActor.mutatingValue
await sampleActor.defaultFunc()

変更不可なデータである定数や nonisolated が付与されている method/computed property は data race が発生しないことが保証されているため複数タスクから同時にアクセスしても問題ありません。そのため、 await を必要とせずにアクセスできます。この状態を「隔離されていない(non-isolated)」と表現します。これについては nonisolated の項目 に記載しています。

sampleActor.constValue
sampleActor.nonisolatedFunc()
sampleActor.computedProperty

関連: nonisolated, await

async

[Swift 5.5~]

1. function 宣言部の async

非同期の function を表します。

func listPhotos(inGallery name: String) async -> [String] {
    let result = // ... some asynchronous networking code ...
    return result
}

DB 操作やネットワーク処理などの非同期の処理を待つ、つまり、途中で関数内の処理を中断・再開するような関数を表します。非同期関数を呼ぶには await を使って結果を待つ(suspension point)ことを明示します。

let photoNames = await listPhotos(inGallery: "Summer Vacation")

2. async let

非同期関数の結果を受け取る変数を宣言します。let thumbnail = await downloadImage(...) とする場合と違い、実際に値を使う部分に到達するまで待機しません。
下記の例では thumbnail と authorImage の download が並列で実行され、値が使われる箇所(let photos = ...)で download の終了を待ちます。

async let thumbnail = downloadImage(url: bookImageUrl) // download 開始
async let authorImage = downloadImage(url: authorImageUrl) // download 開始

let photos = await [thumbnail, authorImage] // thumbnail と authorImage の download が終わるまで待機

関連: await

await

[Swift 5.5~]

1. await + fuction/method

非同期関数の終了を待つ部分(suspension point)を表します。

// download が終わるまで次の処理に進まない。
// (thread を一時的に解放して他の待機中のタスクが実行される)
let photo = await downloadPhoto(named: name)
show(photo)

2. for await-in loop

AsyncSequence に対して loop を回す場合は sequence から要素が渡されるまで待機します。

for await i in Counter(howHigh: 10) {
    print(i, terminator: " ")
}

class

場所によって意味が異なります。

  • クラスの宣言や、メソッドやプロパティの前に指定することでクラスメソッド、クラスプロパティの宣言をします。
class Sample {
    class func f() {}
    class var classProperty: String {
        "classProperty" 
    }
}
  • プロトコルの適用先をクラスだけに制限したい場合(deprecated)

後方互換のためこの用途で機能しますが Swift4 からは AnyObject を使用するのが正しいです。
また、Xcode12.5 から AnyObject に置き換えるように警告が出ます。

// warning: using 'class' keyword for protocol inheritance is deprecated; use 'AnyObject' instead
protocol SampleProtocol: class {} 

class Sample: SampleProtocol {}

参考:

  1. @YOCKOW さんからのコメント
  2. Github Apple/swift PR: [Sema] Adding deprecation warning for protocol inheritance 'class' syntax #34885

deinit

デストラクタの宣言をします。これは class でのみ有効です。
スーパークラスの 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

列挙型の宣言をします。

enum SampleEnum {
    case a
    case b(Int)
}

extension

定義済みのクラス、構造体、プロトコル、列挙型に対して function または computed property を追加します。

extension Array {
    func f() {}
}
let intArray = [1]
intArray.f()

protocol の適合の追加や

extension SampleClass: HogeDelegate {
    func f() {}
}

where で適応する条件を指定できます。

extension Array where Element == Int {
    func funcForIntArray() {}
}
intArray.funcForIntArray()

fileprivate

アクセス修飾子の一種です。
同じファイル内からのアクセスが可能です。

関連: public, private, internal, open
参考: The Swift Programming Language # Access Control

func

function の宣言をします。

import

モジュールを読み込みます。

init

コンストラクタを宣言します。

inout

intout 指定された引数として渡された変数は、function 内での変更が適応されます。(表面的には参照渡しに似た動作になります)

具体的には下記の動作をします。

  1. function の呼び出し時に、引数として与えられた値がコピーされ、そのコピーが function の中で使われます。
  2. function の終了時に引数として与えられた変数にコピーが代入されます。
class SampleClass {}

func inoutSampleForClass(sampleClass: inout 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(a: inout Int) {
    a = 100
}

func withoutInoutSample(var a: Int) {
    a = 100
}

var varInt = 1

// inout なし
withoutInoutSample(varInt)
varInt // => 1

// inout あり
inoutSample(&varInt)
varInt // => 100

参考: In-Out Parameters

internal

アクセス修飾子の一種です。
同じモジュール内からアクセスできます。
アクセス修飾子をつけなかった場合、デフォルトで internal となります。
関連: public, private, open, fileprivate
参考: The Swift Programming Language (Swift 3) # Access Control

let

定数を宣言します。
関連: var

open

アクセス修飾子の一種です。アクセス制限の種類の中で最もアクセス制限の緩い指定です。
外のモジュールからのアクセス、継承・オーバーライドが可能です。
性質上、この制限を指定できるのは class または オーバーライド可能な class member のみです。

public との違いは、継承・オーバーライドの許可範囲 (外のモジュールからの継承・オーバーライド可能性) です。

関連: public, private, internal, fileprivate
参考: The Swift Programming Language # Access Control

operator

独自の演算子を定義します。
演算子として採用できる文字については規定があります。詳細は iOS Developer Library の Language Reference > Lexical Structure > Operators をご覧ください。
関連: prefix, postfix, infix

prefix operator 
prefix func  (a: inout Int) -> Int {
    a *= a
    return a
}
postfix operator ***  // 複数文字列も可能
postfix func *** (a: inout 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

precedencegroup

左右に被演算子をとる演算子の優先度グループを定義します。
higherThan で、どのグループより優先度が高いか指定できます。lowerThan では、他のモジュールのどのグループより優先度が低いか指定できます。associativityassignment も指定できます。

演算子を定義する構文
infix operator <#operator name#> : <#precedence group name#>
+++が先に評価される場合
precedencegroup GroupA {

    associativity: none
}
precedencegroup GroupB {
    
    higherThan: GroupA
    associativity: none
}

infix operator ***: GroupA
infix operator +++: GroupB

func *** (left: Int, right: Int) -> Int {
    return left * right
}
func +++ (left: Int, right: Int) -> Int {
    return left + right
}

1 +++ 1 *** 0  // => 0

関連: operator, associativity, assignment

private

アクセス修飾子の一種です (型、変数、定数、function の公開範囲の指定)
最も制限の強いアクセス修飾子で、下記の条件を満たす場合のみにアクセスできます。

  • 同じファイル内
  • 同じ型
class A {
    private var privateVar = ""
}

extension A {
    func f() {
        // ✅OK
        print(privateVar)
    }
}

class B {
    let a = A()
    func f() {
        // ❗️error: 'privateVar' is inaccessible due to 'private' protection level
        a.privateVar
    }
}

関連: public, internal, open

protocol

プロトコルを宣言します。

public

アクセス修飾子の一種です (クラス、変数、定数、メソッド、関数の公開範囲の指定)
同じターゲット(モジュール)外からアクセス可能になります。open と異なり、継承は禁止されます。
主に、ライブラリなどで API として公開するものに対して指定します。
関連: private, internal, open

static

static 変数や static function を宣言します。
protocol での宣言時 (下記参照) は class funcclass var も意味に含みます。

protocol SampleProtocol {
    static func staticFuncInProtocol()
    static var staticVarInProtocol: Int { get }
}

class Sample {
    // `static func staticFuncInProtocol()` can be implemented by `static func` or `class func`
    class func staticFuncInProtocol() {}
    // ditto
    class var staticVarInProtocol: Int { 1 }
}

some

型の前に記述され、呼び出し元に対して具体的な型情報を隠蔽します。(ただし、コンパイラは具体的な型情報を知っている状態となります)

詳細

SwiftUI では下記のように使われています。

var body: some View {
    Text("Hello, World!")
}

body の内部では Text という concrete type(具体的な型)を返していますが、呼び出し元では Text 型とは分からない状態です。分かるのは、「View に準拠した"とある(some)"型である」ということです。

それならば、some がなくても同じだと思うかもしれません。

var body: View {
    Text("Hello, World!")
}

この場合でも具体的な型情報は隠蔽されています。しかし、この場合はコンパイラにも抽象型として扱われます。
一方、some をつけた場合、コンパイラには具体的な型情報がわかっています。「concrete type(具象型)であるが、呼び出し元からは具体的に何の型かは分からない」という状態で扱われます。

参考: the swift programming language/Opaque Types

struct

構造体を宣言します。

subscript

クラスや構造体に [] を実装します。
Objective-C の場合についてはクラスに [], {} を実装するに書いてみました。

実装例
class SubscriptSample {
    var hoge: Any?
    subscript(index: Int) -> String {
        get {
            return "Int もらいました"
        }
        set {
            hoge = newValue
        }
    }
    
    subscript(index: String) -> String {
        get {
            return "String もらいました"
        }
        // setter なくても良いです
    }
    
    subscript(index: AnyObject?) -> String {
        return "何かもらいました"
    }
    
    subscript(x: Int, y: Int) -> String {
        return "\(x), \(y)"
    }

    subscript() -> String {
        return "nothing"
    }
}
使用例
let subscriptSample = SubscriptSample()
var optionalSample: Int? = 1;
subscriptSample[3]     // => "Int もらいました"
subscriptSample["a"]   // => "String もらいました"
subscriptSample[nil]   // => "何かもらいました"
subscriptSample[optionalSample]  // => "何かもらいました"
subscriptSample[1, 2]  // => "1, 2"
subscriptSample[]  // => "nothing"

typealias

型の別名を宣言(*1)、または、associated type に対して型を指定(*2)します。

型の別名を宣言(*1)
typealias IntAlias = Int
typealias Point = (Int, Int)
付属型に対して型を指定(*2)
protocol P {
    associatedtype T
}

struct S: P {
    typealias T = Any
}

参考:
The Swift Programming Language (Language Reference -> Declaration -> Type Alias Declaration)
The Swift Programming Language (Language Reference -> Declaration -> Protocol Associated Type Declaration)

associatedtype

associated type (付属型) の宣言をします。

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 {
        i += 1
        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 {
        i += 1
        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 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 文の次の case 文または default 文内の処理を実行します。
(厳密には、fallthrough の所属している case ブロックの中から抜け、所属する case 文の次の case 文または default 文内の処理を実行します)

使用例
let a = 1
switch a {
case 1:
    print("1")
    fallthrough
case 2:
    print("2")
default:
    print("default")
}
C言語の場合(上記と同等の処理)
switch (a) {
case 1:
    printf("1\n");
case 2:
    printf("2\n");
    break;
default:
    printf("default\n");
}
1
2

補足

下記の補足です。

厳密には、fallthrough の所属している case ブロックの中から抜け、所属する case 文の次の case 文または default 文内の処理を実行します。

下記のように、fallthrough が呼ばれると、即座に case ブロックから抜けます。
そのため、その下の print("1-2") は実行されません。

switch 1 {
case 1:
    defer { print("defer") }  // ブロック(スコープ) から抜ける様子を観察
    print("1-1")
    if true {
        fallthrough
    }
    print("1-2")
case 2:
    print("2")
default:
    print("default")
}
1-1
defer
2

for

繰り返し処理を記述できます。

for-in
for i in 1...10 {
    // 処理
}

for _ in 1...10 {
    // 処理
}

関連: in, while

guard

変数または定数が条件に一致するか評価し、一致していない場合、続く else のブロックが実行されます。
このブロックの中では必ず以下のいずれかを使用し、guard が記述されているスコープを抜けなくてはいけません。

func guardSample1(value: Int?) -> String {
    guard let value = value, 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 {
        type(of: value) // Optional<Int>.Type
        type(of: a)     // Int.Type
    }
}

関連: else, guard

in

文脈によって下記のように意味が変わります。

  • クロージャのボディの開始箇所を表します
  • for ~ in の形で取り出す要素の配列を指定します

関連: for

repeat

C言語等の言語における

do {...} while(...)

do の役割です。
関連: while

return

返り値を指定します。
返り値は下記の 2 パターンです。

  • 要素が一つの場合はその要素
  • それ以外の場合は tuple
func sample() {
    return
}
var a = sample() // -> ()

参考: Remove @noreturn attribute and introduce an empty Never type

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

any

型が existential type であることを明示します。
any での明示は Swift5 では必須ではありませんが、Swift6 からは必須です。
(ただし、AnyAnyObject に対しては any は必須ではありません。)

詳細

例えば、protocol P に準拠した型を P 型に抽象化して(existential type として)扱いたい場合を考えます。let p1: any P = S() のように型の宣言部に any をつけることで、ここでの P が existential type であることを明示できます。

protocol P {}
struct S: P {}

let p1: any P = S()

参考: Introduce existential any

Any

すべての型のインスタンス (関数型も含む) を表現します。
実態は空の protocol です。

参考:
Type Casting for Any and AnyObject
Import Objective-C id as Swift Any type

catch

例外が投げられた際にブロック内が実行されます。

false

真偽値リテラルの一種で、偽を表します。

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

nil リテラルを表します。

Optional.None == nil // -> true

rethrows

引数にとったクロージャが投げた例外を呼び出し元に対して更に投げます。

func sample(callback: () throws -> Int) rethrows {
    try callback()
}

super

親クラスを表します。

self

インスタンスメソッド内などで単独で使用した場合、インスタンス自身を返します

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

真偽値リテラルの一種で、真を表します。

try

例外が投げられる可能性のある関数・メソッドを実行します。

Keywords that begin with a number sign (#)

#available

OS 及びそのバージョンによる条件を表現します。

if #available(iOS 10.0, *) {
    print("iOS10 or later")
}

関連: #unavailable

#unavailable

[Swift 5.6~]
OS 及びそのバージョンによる条件を表現します。

if #unavailable(iOS 15.0) {
    // Old functionality
} else {
    // iOS 15 functionality 
}

関連: #available

#colorLiteral

下記の構文で色を表現するリテラルを記述できます。

#colorLiteral­(­red­:­ <# expression #>­, ­green­:­ <# expression #>­,­ blue­:­ <# expression #>­,­ alpha­: <# expression #>­)­

型を明示しない場合は、AppKit モジュールをインポートした場合は NSColor 型、UIKit モジュールをインポートした場合は UIColor 型として解釈されます。

#column

#column が評価された場所の列番号 (Int)

#if, #else, #elseif, #endif

コンパイル時に指定のコードを含めるか否かを制御します。

条件例
#if <# Custom Flag に設定した名前 (設定せずにコンパイルすると無視される) #>
  print("DEBUG")
#endif

#if swift(>=3.0)
  print("Swift3.0")
#endif

#if arch(arm64)
  print("arm64")
#endif

#if os(OSX)
  print("OSX")
#endif
Swiftのバージョンを条件に制御する例
#if swift(>=3.0)
    print(">=Swift3.0")
#elseif swift(>=2.0)
    print(">=Swift2.0")
#else
    print("else")
#endif

参考:

#error

記載した行に対するエラーを compile 時に発生させます。
error warning
関連: #warning

#file

#file が評価された場所のパス(String)を返します。
ただし、今後の Swift のバージョンで動作の変更があるため #fileID#filePath への置き換えが推奨されています。
Swift5.5時点では #filePath と同じ動作をしますが、今後のバージョンでは #fileID の動作へ変更されます。

// sample project の中の sampleApp.swift で使った場合
print("#file", #file)
print("#filePath", #filePath)
print("#fileID", #fileID)
出力
#file /Users/ezura/workspace/article/swift5/sample/sampleApp.swift
#filePath /Users/ezura/workspace/article/swift5/sample/sampleApp.swift
#fileID sample/sampleApp.swift

関連: #filePath, #fileID

参考: the swift programming language > Expressions > Literal Expression

#fileID

#fileID が評価されたファイルとそのモジュール名を module名/file名 の形式で返します(String型)。

// sample project の中の sampleApp.swift で使った場合
print("#fileID", #fileID)
出力
#fileID sample/sampleApp.swift

関連: #filePath, #file
参考: the swift programming language > Expressions > Literal Expression

#filePath

#filePath が評価された場所のパス(String)を返します。

// sample project 内の sampleApp.swift で使った場合
print("#filePath", #filePath)
出力
#filePath /Users/ezura/workspace/article/swift5/sample/sampleApp.swift

関連: #file, #fileID
参考: the swift programming language > Expressions > Literal Expression

#fileLiteral

下記の構文でファイルリテラルを記述できます。

#fileLiteral(resourceName: "<# ファイル名 #>")

型を明示しない場合は URL 型として解釈されます。(Foundation モジュールがインポートされている場合のみ)
また、ファイルが取得できなかった場合、実行時エラーとなります。

参考:

#function

#function が評価された場所の関数・メソッドの名前 (String) を表現します。

#imageLiteral

下記の構文で画像リソースを表現するリテラルを記述できます。

#imageLiteral(resourceName: "<# ファイル名 #>")

型を明示しない場合は、AppKit モジュールをインポートした場合は NSImage 型、UIKit モジュールをインポートした場合は UIImage 型として解釈されます。

#keypath

key や keypath (string literal) を生成します。

class Object: NSObject {
    let value = 1
    var matryoshka: Object?
}

#keyPath(Object.value)  // "value"
#keyPath(Object.matryoshka.value)  // "matryoshka.value"

let object = Object()
object.matryoshka = Object()

object.value(forKey: #keyPath(Object.value))  // 1
object.value(forKeyPath: #keyPath(Object.matryoshka.value))  // 1

関連:

#line

#line が評価された場所の行番号 (Int)

#selector

Selector を生成します。

Swift3 から、以前の機能に加えて Objective-C で記述された class のプロパティの getter, setter メソッドの Selector を \#selector を用いて生成できるようになりました。(以前は \#selector が対応していなかったため、文字列で指定していました)

@interface ViewController : UIViewController
@property(assign) int num;
@end
#selector(getter: ViewController.num)
#selector(setter: ViewController.num)

参考:

#sourceLocation

#line, #file, #filePath, #fileID の値を操作します。

  • 値の変更: #sourceLocation(file: file path, line: line number)
  • 変更をリセット: #sourceLocation()
    sourceLocation.png
    ただし、Playground 上ではリセット後の line の値が不正になるバグがあります。(Xcode13.1時点で確認)
    参考:The Swift Programming Language > Line Control Statement

#warning

記載した行に対する warning を compile 時に発生させます。
error warning
関連: #error

#dsohandle

#line, #file, #function と同様に、書かれている場所に関する情報を表すキーワードです。
自身が書かれているライブラリがロードされている場所のアドレスを表します。(アドレスなので、他のキーワードと違い、UnsafePointer型です)

provides an UnsafePointer to the current dynamic shared object (.dylib or .so file)
引用: Modernizing Swift's Debugging Identifiers

特定の文脈でのみ予約語として使用

assignment

左右に値を取る演算子を宣言した際に、Optional Chaining 評価の一連の流れで演算するかを指定します。
true を指定すると、Optional Chaining 評価の一環として演算を行おうとします。false は既定の動作で、Optional Chaining の評価が終わってから、その評価結果と演算します。

オプショナルチェイニングでの畳み込み
precedencegroup OperationFoldedIntoOptionalChaining {
    assignment: true
}

precedencegroup OperationOutsideOfOptionalChaining {
    assignment: false
}

infix operator ~~ : OperationFoldedIntoOptionalChaining
infix operator ~^ : OperationOutsideOfOptionalChaining

func ~~ (left: Int, right: Int) -> Int {
    print("~~")
    return left + right
}

func ~^ (left: Int?, right: Int) -> Int {
    print("~^")
    return left?.advanced(by: right) ?? -1
}

let values = nil as [Int]?

values?.count ~~ 5  // => nil
values?.count ~^ 5  // => -1

/*
    ~~ 演算は、
        最初に `values` の nil 判定、nil でなければ `.count ~~ 5` を評価
        values.map { $0.count ~~ 5 } と同等。この例では `~~` 演算は実行されない。

    ~^ 演算は、最初に `values?.count` を評価、続いて `その結果 ~^ 5` を評価
        普通に `(values?.count) ~^ 5` としたのと同等。演算子の既定の動作。
*/

関連: infix, operator, precedencegroup

associativity

左右に値を取る優先度グループを宣言した際に、結合方向を指定します。
指定できる値は下記の 3 種類です。

  • left
  • right
  • none: 結合方向を指定しないため、同じグループの演算子同士を並べて使用することができなくなります。
優先度グループを定義する構文
precedencegroup <#precedence group name#> {
    higherThan: <#lower group name#>
    associativity: <#left | right | none#>
}
同優先度、結合方向 none
precedencegroup MyAddition {
    associativity: none
}

infix operator +++ : MyAddition
infix operator --- : MyAddition

func +++ (left: Int, right: Int) -> Int {
    return left + right
}

func --- (left: Int, right: Int) -> Int {
    return left - right
}

1 +++ 1 --- 1
/*
 error: adjacent operators are in non-associative precedence group 'MyAddition'
 1 +++ 1 --- 1
   ^     ~~~
 */

関連: left, right, none, operator, precedencegroup

convenience

init の前に記述することで、convenience initializer を宣言します。
関連: init

dynamic

Objective-C のランタイムを使用して値にアクセスします。

構文
dynamic <#var | let #> <# name #>

詳細

Objective-C runtime と pure Swift では、呼び出す処理を決定する方法 (method dispatch) が異なります。
Objective-C runtime の場合、実行時に Class に対して問い合わせて実行すべき処理を探していきます (message passing 方式)。
例えば、instance.methodA() を実行するとき、instance の持つ Class の情報に対して、"methodA" (呼び出したい function 名) があるか検索します。無かったらその Class の親 Class に対して問い合わせる、なかったら更にその親 Class に、といった処理を実行時に行います。
一方、Swift ではコンパイル時に「型に対してどんな method があるか」という情報を持つ table を作ります。直接呼び出す場合もありますが、継承関係がある場合など、実行時にしか呼び出す処理が決まらない場合はこの table を参照して処理を決定します。重要なのは、この table はコンパイル時に作られてから後で変更できないということです。
Objective-C の場合、Class の情報を書き換えることができます。つまり、実行時に method を増やしたり、method 名を変えたり、処理を入れ替えたりできます。(method swizzling と呼ばれる操作です)
このような Objective-C の機能を使いたい場合、dynamic を指定することで、Swift の method table 上には載らず、Objective-C の機構を使って処理するようになります。

didSet

Stored プロパティまたは変数の値が変更された際の処理を宣言します。

final

継承、オーバーライドを不可にします。

get

文脈によって意味が異なります。

computed property 内: プロパティにアクセスした際の処理

class A {
    var value: Int {
        get { return 1 }
    }
}

protocol 内で宣言した場合: 値が取得可能であることの宣言

protocol Sample {
    var value: Int { get }
}

class A: Sample {
    let value = 1
}

class B: Sample {
    var value: Int { return 1 }
}

infix

左右に被演算子をとる演算子の処理を定義します。

infix operator 
func  (left: Int, right: Int) -> Int {
    return left + right
}

1  2    // => 3

関連: operator

indirect

列挙体を列挙子の中で再帰的に使えるようになります。つまり、Json のような入子構造を表現できます。

enum SampleEnum {
    case num(Int)
    indirect case indirectNum(SampleEnum)
}

または

indirect enum SampleEnum {
    case num(Int)
    case IndirectNum(SampleEnum)
}
// 入子にできる
SampleEnum.indirectNum(
    .indirectNum(
        .indirectNum(
            .num(1)
        )
    )
)

詳細:
indirect を指定すると associated value を間接指定するようになります。
間接指定しない場合、associated value 分のメモリサイズが確定できないため、その列挙体のために確保するメモリサイズも決まりません。
間接指定する場合、associated value の場所(アドレス)を保持することになるので列挙体のサイズが確定できるようになります。

詳細: Swift Programming Language (Enumerations -> Recursive Enumerations)

lazy

変数を初期化する際の値を遅延評価します。
通常 property は instance の作成時に値が評価されますが、下記のように lazy を指定すると該当の property に初めてアクセスした際に値が評価されます。

class Sample {
    lazy var lazyValue = Date()
    let defaultValue = Date()
}

let sample = Sample()
sleep(10)
// lazyValue 2021-11-18 05:14:47 +0000
print("lazyValue", sample.lazyValue)
// defaultValue 2021-11-18 05:14:37 +0000
print("defaultValue", sample.defaultValue)

使い所としては、

  1. 該当のpropertyに入る値の生成にコストがかかるため、実際に使うときまでその生成を遅延させたい場合
  2. init 時に値が決まらないため、後で値を代入したい場合

があります。
2 番目に関しては少々トリッキーなので好みが分かれますが、下記のように IUO を避ける実装ができます。

class Sample {
    var iuoValue: String! // init 時に値が決まらないため IUO にしている
    // ↑のようなIUO を使うのを避ける実装。最初は`Never`(全ての型のサブタイプ扱い)を返すclosure
    を入れておきこのpropertyにアクセスする前には値を入れる前提
    lazy var lazyEval: String = { preconditionFailure() }()
}

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

nonisolated

[Swift 5.5~]
Actorの宣言部で使用します。
Actor の基本思想は「ミュータブルなデータ(状態)を actor 外から隔離(isolate)しデータの同期状態を守る」ことです。そのため、actor の method や mutable な property はデフォルトで隔離(isolate)対象となっています。
その対象としないことを指定する場合に nonisolated を付与します。

actor SampleActor {
    nonisolated func nonisolatedFunc() {}
    nonisolated var nonisolatedComputedProperty: String {
        "computedProperty getter"
    }
}

ミュータブルなデータ(状態)の保護状態を守るため、隔離対象外(nonisolated)の method/computed property は隔離対象の property や method へのアクセスが禁止されます。これに違反するとコンパイルエラーになります。
actor nonisolated context error
関連: actor

nonmutating

値型のインスタンスメソッドが自身に変更を加えないことを宣言します。

使い所:
computed property 内で定義する set はデフォルトで mutating 指定になります。iOS の API 内では下記のように setter の mutaing を無効にするために使用しています。

var value: Value { get nonmutating set }

optional

プロトコルで指定されたメソッドやプロパティの実装を任意とします。

override

親クラスのメソッドやプロパティをオーバーライドする際に宣言します。

postfix

独自の後置演算子を定義します。

postfix operator ***
postfix func *** (a: inout Int) -> Int {
    a *= a
    return a
}
var hoge = 4
hoge***  // => 16

関連: prefix, infix, operator

prefix

独自の前置演算子を定義します。

prefix operator ***
prefix func *** (a: inout Int) -> Int {
    a *= a
    return a
}
var hoge = 4
***hoge  // => 16

関連: postfix, infix, operator

Protocol

Protocol のメタタイプを取得します。

let protocolMetatype: SampleProtocol.Protocol = SampleProtocol.self

関連: Type

required

サブクラスにイニシャライザのオーバーライドを強制します。
また、サブクラスでそのイニシャライザをオーバーライドする際には override ではなく、required を指定します。

right

演算子を定義した際に、右結合を指定します。
詳細: このページの associativity 項
関連: associativity, operator, left, none

set

文脈によって意味が異なります。

computed property 内: プロパティにアクセスした際の処理

class A {
    var value: Int {
        get { return 1 }
        set {}
    }
}

protocol 内で宣言した場合: 値を受け渡し可能であることを宣言

protocol Sample {
    var value: Int { get set }
}

class A: Sample {
    var value = 1
}

class B: Sample {
    var value: Int {
        get { return 1 }
        set {}
    }
}

Type

クラス、構造体、列挙体のメタタイプを取得します。

class Sample {
    required init() {}
}

let metatype: Sample.Type = Sample.self
let instance = metatype.init()

関連: Protocol

unowned

弱参照の変数を宣言します。
weak と違い、参照している値よりも生存期間が短い、つまり、アクセスした際に参照先が解放されていない (nil となっていない) ことを前提とします。値が破棄されているとランタイムエラーになります。

// unowned = unowned(safe)
unowned var safe: AnyObject

// capture list 内で指定することが多いです
{ [unowned a] in /* ... */ }

関連: weak, unowned(safe), unowned(unsafe)

unowned(safe)

unowned へ修飾することで参照の動作を指定できます。
unowned(何も指定しなかった場合)は unowned(safe) 扱いとなります。関連する指定に unowned(unsafe) があります。

// unowned = unowned(safe)
unowned(safe) var safe: AnyObject

// capture list 内で指定することが多いです
{ [unowned(safe) a] in /* ... */ }

関連: unowned(unsafe), unowned

unowned(unsafe)

unowned へ修飾することで参照の動作を指定できます。
unowned または unowned(safe) と違い、参照先が解放された際にアクセスしても nil と評価されません。つまり、解放されている場所を指し続けているためメモリに対して安全なアクセスをしません。
Objective-C の __unsafe_unretained と同様の動作です。

// like `__unsafe_unretained`
unowned(unsafe) var unsafe: AnyObject
{ [unowned(unsafe) a] in /* ... */ }

関連: unowned(safe), unowned

weak

弱参照の変数を宣言します。
unowned と違い、参照している値が nil になることを許容します。

willSet

stored property または変数への代入が実行される前の処理を記述します。
関連: didSet

その他

_

ワイルドカード

switch (1, "a") {
case (1, "b"):
    print("1, b")
case (1, _):
    print("1, _")  // ここがマッチします。 (_ はワイルドカード)
}

関連: case

引数名の省略

引数が必要なinit
class Sample {
    var a: Int
    init(param: Int) {
        a = param
    }
}
let sample = Sample(param: 1)
引数が不要なinit
class Sample {
    var a: Int
    init(_ param: Int) {
        a = param
    }
}
let sample = Sample(1)

値を捨てる

let a: Int
(a, _) = (0, 1)
a // -> 0

型の補完(Type placeholder)

Swift5.6〜
型を宣言する部分に対して _ を記述するとその部分が型推論される。
つまり、型の明示を省略できる。

let dict: [_: String] = [0: "zero", 1: "one", 2: "two"]
// -> [Int: String]

let count: _? = 0
// -> Int?

参考:
Type placeholders (formerly, "Placeholder types")

82
39
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
82
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?