プロトコル


プロトコル は、特定のタスクや機能の一部に適するメソッド、プロパティ、およびその他の要件の青写真を定義します。プロトコルは、それらの要件の実際の実装を提供するために、クラス、構造体、または列挙型によって 採用 されます。プロトコルの要件を満たす全ての型は、そのプロトコルに 準拠する と言われます。


適合する型が実装しなければならない要件を指定する事に加え、プロトコルを拡張して、これらの要件の一部を実装するか、適合する型が活用できる追加の機能を実装できます。


プロトコルの構文


クラス、構造体、列挙型と非常に似た方法でプロトコルを定義できます。


  1. protocol SomeProtocol {
  2.         // protocol definition goes here
  3. }


カスタム型は、特定のプロトコルを採用すると述べるのに、それらの定義の一部として、プロトコルの名前をコロンで区切って型の名前の後に書きます。複数のプロトコルを一覧表示でき、カンマで区切られます。


  1. struct SomeStructure: FirstProtocol, AnotherProtocol {
  2.         // structure definition goes here
  3. }


クラスがスーパークラスを持っている場合、それが採用する全てのプロトコルの前にスーパークラス名を一覧表示し、コンマを続けます。


  1. class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
  2.         // class definition goes here
  3. }


プロパティの要件


プロトコルは、インスタンスプロパティや、特定の名前と型を持つ型プロパティを提供するために、全ての準拠する型を必要とします。プロトコルはプロパティが格納されたプロパティか計算されたプロパティかを指定する必要はありません-必要なプロパティ名と型だけを指定します。プロトコルはまた、各プロパティが取得可能か、取得可能 かつ 設定可能でなければならないと指定します。


プロトコルが取得可能かつ設定可能なプロパティを必要とする場合、そのプロパティの要件は、定数の格納されたプロパティまたは読み取り専用の計算されたプロパティで満たすことはできません。プロトコルはプロパティが取得可能であることのみを必要とする場合、要件は、プロパティの全ての種類によって満たされ、自分のコードに便利であればプロパティは設定可能でもありえます。


プロパティの要件は、常に var キーワードで始まる変数プロパティとして宣言されます。取得可能かつ設定可能なプロパティは、その型宣言の後に { get set } と書くことで示され、取得可能プロパティは { get } と書くことで示されます。


  1. protocol SomeProtocol {
  2.         var mustBeSettable: Int { get set }
  3.         var doesNotNeedToBeSettable: Int { get }
  4. }


プロトコルで定義した時には、static のキーワードの前に、必ず型プロパティの要件を付けます。この規則は、型プロパティ要件がクラスによって実装されて classstatic キーワードが前に付けていてもあてはまります:


  1. protocol AnotherProtocol {
  2.         class var someTypeProperty: Int { get set }
  3. }


ここでは一つのインスタンス・プロパティ要件を持つプロトコルの例を示します。


  1. protocol FullyNamed {
  2.         var fullName: String { get }
  3. }


FullyNamed プロトコルは、完全に修飾された名前を提供するために準拠する型を必要とします。プロトコルは準拠する型の性質について他のものは指定しません-それはその型がフルネームをそれ自身で提供できなければならないことのみを指定します。プロトコルはどんな FullyNamed 型でも String 型の fullName と言う取得可能なインスタンス・プロパティを持っていなければならないことを述べています。


ここで FullyNamed プロトコルに準拠し、採用する簡単な構造体の例を示します。


  1. struct Person: FullyNamed {
  2.         var fullName: String
  3. }
  4. let john = Person(fullName: "John Appleseed")
  5. // john.fullName is "John Appleseed"


この例では、特定の名前の人を表す Person と言う構造体を定義しています。それは、その定義の最初の行の一部として FullyNamed プロトコルを採用していると述べています。


Person の各インスタンスには、String 型の fullName と言う一つの格納されたプロパティがあります。これは FullyNamed プロトコルの一つの要件に一致し、Perso が正しくプロトコルに準拠していることを意味します。(プロトコル要件が満たされていない場合、Swift はコンパイル時にエラーを報告します。)


ここで FullyNamed プロトコルに準拠し採用した、より複雑なクラスを挙げます。


  1. class Starship: FullyNamed {
  2.         var prefix: String?
  3.         var name: String
  4.         init(name: String, prefix: String? = nil) {
  5.                 self.name = name
  6.                 self.prefix = prefix
  7.         }
  8.         var fullName: String {
  9.                 return (prefix != nil ? prefix! + " " : "") + name
  10.         }
  11. }
  12. var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
  13. // ncc1701.fullName is "USS Enterprise"


このクラスは、宇宙船の、計算された読み取り専用のプロパティとして fullName プロパティの要件を実装しています。各 Starship クラスインスタンスは、必須の name と optional の prefix を格納します。fullName プロパティは、存在する場合は prefix 値を使用し、宇宙船のフルネームを作成するために、name の先頭にそれを付けます。


メソッドの要件


プロトコルは特定のインスタンスメソッドと型メソッドを型に準拠することで実装される事を要求できます。これらのメソッドは、通常のインスタンスと型メソッドとまったく同じ方法で、プロトコルの定義の一部として書かれますが、中括弧またはメソッド本体はありません。可変個のパラメータは、通常のメソッドの場合と同じ規則に従い、許可されています。しかし、デフォルト値はプロトコルの定義の中のメソッドパラメーターとしては指定できません。



型プロパティの要件と同様に、これらがプロトコル内で定義されている場合、static キーワードを型メソッドの要件の前に常に付けて下さい。型メソッド要件がクラスによって実装されていて class または static キーワードが前に付けていてもこれは当てはまります。


  1. protocol SomeProtocol {
  2.         static func someTypeMethod()
  3. }


以下の例では、一つのインスタンスメソッド要件を持つプロトコルを定義しています。


  1. protocol RandomNumberGenerator {
  2.         func random() -> Double
  3. }


このプロトコル、RandomNumberGenerator は、それが呼び出されるたびに Double 値を返す random と言うインスタンスメソッドを持つ、すべての準拠する型が必要です。それはプロトコルの一部として指定されていませんが、この値は最小 0.0 から最大 1.0 (を含まない) までの数であると仮定されています。


RandomNumberGenerator プロトコルは、各乱数がどう発生されるかについての仮定は全くしていません。単に新しい乱数を発成するための標準的な方法を提供する発生プログラムが必要です。


ここで RandomNumberGenerator プロトコルを採用し準拠したクラスの実装を行います。このクラスは、線形合同法 として知られている擬似乱数生成アルゴリズムを実装しています。


  1. class LinearCongruentialGenerator: RandomNumberGenerator {
  2.         var lastRandom = 42.0
  3.         let m = 139968.0
  4.         let a = 3877.0
  5.         let c = 29573.0
  6.         func random() -> Double {
  7.                 lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
  8.                 return lastRandom / m
  9.         }
  10. }
  11. let generator = LinearCongruentialGenerator()
  12. print("Here's a random number: \(generator.random())")
  13. // prints "Here's a random number: 0.37464991998171"
  14. print("And another one: \(generator.random())")
  15. // prints "And another one: 0.729023776863283"


変異メソッドの要件


メソッドにとって、それが属するインスタンスを変更 (または 変異) することが必要なことがあります。値型のインスタンスメソッド (つまり、構造体と列挙型) の場合、メソッドは、そのインスタンスの全てのプロパティおよびそれが属するインスタンスを変更することが許可されていることを示すために、メソッドの func キーワードの前に、mutating キーワードを配置します。このプロセスは、インスタンスメソッド内から値型を変更 に記載されています。


プロトコルを採用する、全ての型のインスタンスを変異させることを意図しているプロトコル・インスタンス・メソッドの要件を定義する場合、プロトコルの定義の一部として mutating キーワードでメソッドをマークします。これは、プロトコルを採用し、そのメソッドの要件を満たすのを構造体や列挙型に可能にします。


注意: mutating でプロトコル・インスタンス・メソッドの要件をマークする場合は、クラスの、そのメソッドの実装を書くときには mutating キーワードを記述する必要はありません。mutating キーワードは、構造体と列挙型によってのみ使用されます。


以下の例は、toggle と言う一つのインスタンス・メソッドの要件を定義する、Togglable と言うプロトコルを定義しています。その名前が示唆するように、toggle() メソッドは、典型的には、その型のプロパティを変更することによって、トグルまたは全ての準拠型の状態を反転することを意図しています。


toggle() メソッドは Togglable プロトコル定義の一部として mutating キーワードでマークされていますが、それが呼び出された時、メソッドが準拠するインスタンスの状態を変異させることが期待されていることを示すためです:


  1. protocol Togglable {
  2.         mutating func toggle()
  3. }


構造体または列挙型のため Togglable プロトコルを実装する場合、その構造体または列挙型も mutating としてマークされている toggle() メソッドの実装を提供することにより、プロトコルに準拠することができます。


以下の例は、OnOffSwitch と呼言う列挙型を定義します。この列挙型は、onoff 列挙型の case で示される二つの状態の間で切り替えます。列挙型の toggle の実装は Togglable プロトコルの要件に一致させるため、mutating としてマークされています:


  1. enum OnOffSwitch: Togglable {
  2.         case off, on
  3.         mutating func toggle() {
  4.                 switch self {
  5.                 case .off:
  6.                         self = .on
  7.                 case .on:
  8.                         self = .off
  9.                 }
  10.         }
  11. }
  12. var lightSwitch = OnOffSwitch.off
  13. lightSwitch.toggle()
  14. // lightSwitch is now equal to .on


イニシャライザの要件


プロトコルは準拠する型によって実装される特定のイニシャライザを必要とします。中括弧またはイニシャライザ本体なしで、通常のイニシャライザと完全に同じ方法で、プロトコルの定義の一部としてこれらのイニシャライザを記述して下さい。


  1. protocol SomeProtocol {
  2.         init(someParameter: Int)
  3. }


プロトコルイニシャライザ要件のクラス実装


指定イニシャライザやコンビニエンスイニシャライザのいずれかとして準拠するクラスのプロトコル・イニシャライザの要件を実装できます。どちらの場合でも、required 修飾子でイニシャライザの実装をマークすしなければなりません。


  1. class SomeClass: SomeProtocol {
  2.         required init(someParameter: Int) {
  3.                 // initializer implementation goes here
  4.         }
  5. }


required 修飾子の使用は、それらがまた、プロトコルに準拠するように、準拠するクラスのすべてのサブクラス上のイニシャライザ要件の明示的または継承された実装を提供することを保証します。


必須イニシャライザの詳細については、必須イニシャライザ を参照してください。



注意: 最後 (final) のクラスはサブクラス化することはできないので、final 修飾子でマークされているクラスを required 修飾子でプロトコル・イニシャライザの実装をマークする必要はありません。final 修飾子の詳細については、オーバーライドの防止 を参照してください。


サブクラスがスーパークラスからの指定イニシャライザを上書きし、また、プロトコルから一致するイニシャライザの要件を実装する場合、requiredoverride 修飾子の両方ともにより、イニシャライザの実装をマークして下さい。


  1. protocol SomeProtocol {
  2.         init()
  3. }
  4. class SomeSuperClass {
  5.         init() {
  6.                 // initializer implementation goes here
  7.         }
  8. }
  9. class SomeSubClass: SomeSuperClass, SomeProtocol {
  10.         // "required" from SomeProtocol conformance; "override" from SomeSuperClass
  11.         required override init() {
  12.                 // initializer implementation goes here
  13.         }
  14. }


失敗可能イニシャライザの要件


失敗可能イニシャライザ で定義されているように、プロトコルは、準拠する型の失敗可能イニシャライザの要件を定義できます。


失敗可能イニシャライザの要件は準拠する型での失敗可能または失敗不可能なイニシャライザによって満たされます。失敗不可能イニシャライザの要件は失敗不可能イニシャライザまたは黙示的に開封された失敗可能イニシャライザによって満たされます。


型としてのプロトコル


プロトコル自体は、実際には、何も機能を実装しません。それにもかかわらず、作成した全てのプロトコルは、コードで使用するための本格的な型になります。


それは型であるため、他の型は以下の物を含む、多くの場所でプロトコルを使用することができます。


注: プロトコルは型であるため、大文字でそれらの名前を始めます (例えば FullyNamedRandomNumberGenerator など) が、これは Swift の他の型の名前と一致するようにです (Int,String,Double など)。


ここでは型として使用されるプロトコルの例を示します。


  1. class Dice {
  2.         let sides: Int
  3.         let generator: RandomNumberGenerator
  4.         init(sides: Int, generator: RandomNumberGenerator) {
  5.                 self.sides = sides
  6.                 self.generator = generator
  7.         }
  8.         func roll() -> Int {
  9.                 return Int(generator.random() * Double(sides)) + 1
  10.         }
  11. }


この例では、ボードゲームで使用するための n 面のサイコロを表す Dice と言う新しいクラスを定義しています。Dice インスタンスは、それらに何面あるかを表す sides と言う整数プロパティ、およびサイコロを転がして出る値を作成する、乱数発生器を提供する generator と言うプロパティがあります。


generator プロパティは、RandomNumberGenerator 型です。したがって、RandomNumberGenerator プロトコルを採用する 全ての 型のインスタンスにそれを設定できます。このインスタンスが RandomNumberGenerator プロトコルを採用しなければならないことを除いて、このプロパティに代入するインスタンスの要件は他にありません。


Dice にはまた、その初期状態を設定するために、イニシャライザがあります。このイニシャライザには、RandomNumberGenerator 型でもある generator と言うパラメータがあります。新しい Dice インスタンスを初期化するときには、このパラメータに、任意の準拠型の値を渡す事ができます。


Dice は 1 とサイコロの面の数の間の整数値を返す一つのインスタンス・メソッド、roll を提供します。このメソッドは、0.01.0 の間の新しい乱数を作成するための発生器の random() メソッドを呼び出して、正しい範囲内のサイコロの値を作成するために、この乱数を使用します。generatorRandomNumberGenerator を採用する事がわかっているので、呼び出すための random() メソッドがあることが保証されています。


ここで Dice クラスは、その乱数発生器として LinearCongruentialGenerator インスタンスで6面のサイコロを作成するために使用できる方法を以下に挙げます。


  1. var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
  2. for _ in 1...5 {
  3.         print("Random dice roll is \(d6.roll())")
  4. }
  5. // Random dice roll is 3
  6. // Random dice roll is 5
  7. // Random dice roll is 4
  8. // Random dice roll is 5
  9. // Random dice roll is 4


デリゲート


デリゲート は、別の型のインスタンスへの責任の一部を渡す (又は デリゲート する) 事をクラスや構造体に可能にするデザインパターンです。このデザインパターンは、デリゲートされた責任をカプセル化するプロトコルを定義することによって実装され、準拠する型 (デリゲートとして知られる) がデリゲートされた機能を提供することが保証されるようにします。デリゲートは、特定のアクションに応答するために、またはそのソースの基本型を知らなくても、外部ソースからデータを取得するために使用できます。


以下の例では、サイコロベースのボードゲームで使われる2つのプロトコルを定義しています。


  1. protocol DiceGame {
  2.         var dice: Dice { get }
  3.         func play()
  4. }
  5. protocol DiceGameDelegate {
  6.         func gameDidStart(_ game: DiceGame)
  7.         func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
  8.         func gameDidEnd(_ game: DiceGame)
  9. }


DiceGame プロトコルは、サイコロを使う全てのゲームによって採用されうるプロトコルです。 DiceGameDelegate プロトコルは DiceGame の進行を追跡するために、すべての型で採用される事ができます。


ここで、もともと フロー制御 で導入された 蛇と梯子 のゲームのバージョンを示します。このバージョンは、そのサイコロを振るための Dice インスタンスを使用するように、DiceGame プロトコルを採用するように適合されています。その進行状況について DiceGameDelegate に通知します:


  1. class SnakesAndLadders: DiceGame {
  2.         let finalSquare = 25
  3.         let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
  4.         var square = 0
  5.         var board: [Int]
  6.         init() {
  7.                 board = Array(repeating: 0, count: finalSquare + 1)
  8.                 board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
  9.                 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
  10.         }
  11.         var delegate: DiceGameDelegate?
  12.         func play() {
  13.                 square = 0
  14.                 delegate?.gameDidStart(self)
  15.                 gameLoop: while square != finalSquare {
  16.                 let diceRoll = dice.roll()
  17.                 delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
  18.                 switch square + diceRoll {
  19.                 case finalSquare:
  20.                         break gameLoop
  21.                 case let newSquare where newSquare > finalSquare:
  22.                         continue gameLoop
  23.                 default:
  24.                         square += diceRoll
  25.                         square += board[square]
  26.                         }
  27.                 }
  28.                 delegate?.gameDidEnd(self)
  29.         }
  30. }


蛇と梯子 ゲームプレイの説明については、フロー制御 の章の Break のセクションを参照してください。


ゲームのこのバージョンは、DiceGame プロトコルを採用する SnakesAndLadders というクラスとして包ま込まれています。これは、プロトコルに準拠するために取得可能な dice プロパティ及び play() メソッドを提供します。(dice プロパティは、初期化後に変更する必要がないため、定数のプロパティとして宣言され、プロトコルは、それが取得可能であることのみを要求します。)


蛇と梯子 ゲームボードのセットアップは、クラスの init() イニシャライザの中で行われます。全てのゲームロジックは、そのサイコロを振った値を提供するプロトコルの play メソッドの中に移動し、プロトコルの必須 dice プロパティを使用します。


デリゲートは、ゲームをプレイするために必須でないため、delegate プロパティは、optionalDiceGameDelegate として定義されていることに注意してください。それは、optional の型なので、delegate プロパティは nil の初期値に自動的に設定されます。その後、ゲームの例示には、適切なデリゲートにプロパティを設定するオプションがあります。


DiceGameDelegate は、ゲームの進行状況を追跡するために3つのメソッドを提供します。これら3つのメソッドは、上記の play() メソッド内のゲームロジックに組み込まれており、新しいゲームが始まる時、また新しい順番が始まる時、またはゲームが終了したときに呼び出されます。


delegate プロパティは optionalDiceGameDelegate であるため、play() メソッドは、デリゲートのメソッドを呼び出すたびに、optional の連鎖を使用します。delegate プロパティが nil の場合、これらのデリゲートの呼び出しは、嬉しくも失敗し、エラーを起こしません。delegate プロパティが nil でない場合、デリゲートメソッドが呼び出され、パラメータとして SnakesAndLadders インスタンスが渡されます。


次の例では、DiceGameDelegate プロトコルを採用した DiceGameTracker というクラスを示しています。


  1. class DiceGameTracker: DiceGameDelegate {
  2.         var numberOfTurns = 0
  3.         func gameDidStart(_ game: DiceGame) {
  4.                 numberOfTurns = 0
  5.                 if game is SnakesAndLadders {
  6.                 print("Started a new game of Snakes and Ladders")
  7.                 }
  8.                 print("The game is using a \(game.dice.sides)-sided dice")
  9.         }
  10.         func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
  11.                 numberOfTurns += 1
  12.                 print("Rolled a \(diceRoll)")
  13.         }
  14.         func gameDidEnd(_ game: DiceGame) {
  15.                 print("The game lasted for \(numberOfTurns) turns")
  16.         }
  17. }


DiceGameTrackerDiceGameDelegate が必須とする3つすべてのメソッドを実装します。これは、ゲームが取った順番の数を追跡するために、これらのメソッドを使用します。ゲームが始まると numberOfTurns プロパティをゼロにリセットし、新しい順番が始まるたびにそれを増分し、ゲームが終了した時点での順番の数の合計を出力します。


上に示した gameDidStart(_:) の実装は、プレイされようとしているゲームについてのいくつかの初歩的な情報を印刷する game パラメータを使用しています。game パラメータには DiceGame の型があり、SnakesAndLadders の型ではなく、それで gameDidStart(_:)DiceGame プロトコルの一部として実装されるメソッドとプロパティのみにアクセスし、使用できます。しかし、このメソッドはまだ、基礎となるインスタンスの型を照会するために型キャストを使用できます。この例では、game が実際に舞台裏で SnakesAndLadders のインスタンスであるかどうかをチェックし、そうであれば、適切なメッセージを印刷します。


gameDidStart(_:) メソッドはまた、渡された game パラメータの dice プロパティにもアクセスします。game は、DiceGame プロトコルに準拠することが知られているので、dice プロパティを持つことが保証され、従って gameDidStart(_:) メソッドは、プレイされているゲームの種類にかかわらず、サイコロの sides プロパティにアクセスし、印刷できます。


DiceGameTracker は動作中にどのように見えるかをここに示します:


  1. let tracker = DiceGameTracker()
  2. let game = SnakesAndLadders()
  3. game.delegate = tracker
  4. game.play()
  5. // Started a new game of Snakes and Ladders
  6. // The game is using a 6-sided dice
  7. // Rolled a 3
  8. // Rolled a 5
  9. // Rolled a 4
  10. // Rolled a 5
  11. // The game lasted for 4 turns



拡張機能を持つプロトコル準拠の追加


既存の型のソースコードへのアクセス権を持っていない場合でも、新しいプロトコルに準拠し、採用するために、既存の型を拡張することができます。拡張機能は、既存の型に新しいプロパティ、メソッド、およびサブスクリプトを追加し、そのためプロトコルが要求する全ての要件を追加できます。拡張機能の詳細については、拡張機能 を参照してください。



注意: その準拠が拡張機能におけるインスタンスの型に追加されたとき、型の既存のインスタンスは自動的にプロトコルを採用し、準拠します。


例えば、TextRepresentable と言うこのプロトコルは、テキストとして表現される方法がある、全ての型で実装されます。これは、それ自体の説明、または現在の状態のテキストバージョンです。


  1. protocol TextRepresentable {
  2.         var textualDescription: String { get }
  3. }


以前の Dice クラスは TextRepresentable を採用し、準拠するように拡張できます:


  1. extension Dice: TextRepresentable {
  2.         var textualDescription: String {
  3.                 return "A \(sides)-sided dice"
  4.         }
  5. }


この拡張機能は、Dice がその元の実装で提供していたかのようにまったく同じ方法で新しいプロトコルを採用します。プロトコル名は、コロンで区切られ、型名の後に提供され、プロトコルのすべての要件の実装は、拡張機能の中括弧内に提供されます。


全ての Dice インスタンスは、TextRepresentable として扱えるようになりました:


  1. let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
  2. print(d12.textualDescription)
  3. // prints "A 12-sided dice"


同様に、SnakesAndLadders ゲームクラスは TextRepresentable プロトコルを採用し、準拠するように拡張できます:


  1. extension SnakesAndLadders: TextRepresentable {
  2.         var textualDescription: String {
  3.                 return "A game of Snakes and Ladders with \(finalSquare) squares"
  4.         }
  5. }
  6. print(game.textualDescription)
  7. // prints "A game of Snakes and Ladders with 25 squares"


拡張機能を持つプロトコルの採用を宣言


型がすでにプロトコル要件のすべてに準拠していても、まだそれは、そのプロトコルを採用すると述べていない場合、空の拡張機能を持つプロトコルを採用できます。


  1. struct Hamster {
  2.         var name: String
  3.         var textualDescription: String {
  4.                 return "A hamster named \(name)"
  5.         }
  6. }
  7. extension Hamster: TextRepresentable {}


TextRepresentable が必須の型ならどこでも Hamster のインスタンスは、使用できるようになりました。


  1. let simonTheHamster = Hamster(name: "Simon")
  2. let somethingTextRepresentable: TextRepresentable = simonTheHamster
  3. print(somethingTextRepresentable.textualDescription)
  4. // prints "A hamster named Simon"


注意: 型はその要件を満たすことで自動的にプロトコルを採用する訳ではありません。それらは、常に明示的にプロトコルの採用を宣言しなければなりません。


プロトコル型のコレクション


型としてのプロトコル で述べたように、プロトコルは、型として配列や辞書などのようにコレクションに格納されて使用できます。この例では、TextRepresentable の things の配列を作成します:


let things: [TextRepresentable] = [game, d12, simonTheHamster]



配列内の項目を反復処理し、各項目のテキスト表現を印刷することが可能になりました。


  1. for thing in things {
  2.         print(thing.textualDescription)
  3. }
  4. // A game of Snakes and Ladders with 25 squares
  5. // A 12-sided dice
  6. // A hamster named Simon


thing 定数が TextRepresentable 型であることに注意してください。それは舞台裏では実際のインスタンスはそれらの型であっても、DiceDiceGame、または Hamster 型のいずれかでもありません。それにもかかわらず、それは TextRepresentable 型なので、TextRepresentable な全てには texualDescription プロパティがあることを知られているため、ループを通るたび thing.texualDescription にアクセスするのは安全です。



プロトコルの継承


プロトコルは、1つ以上の他のプロトコルを 継承 でき、それが継承する要件の上にさらに要件を追加できます。プロトコルの継承の構文は、クラス継承の構文に似ていますが、オプションで、カンマで区切られた複数の継承プロトコルを一覧表示します:


  1. protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
  2.         // protocol definition goes here
  3. }


ここでは上に挙げた例から TextRepresentable プロトコルを継承するプロトコルの例を示します。


  1. protocol PrettyTextRepresentable: TextRepresentable {
  2.         var prettyTextualDescription: String { get }
  3. }


この例では、TextRepresentable から継承する新しいプロトコル、PrettyTextRepresentable を定義しています。 PrettyTextRepresentable を採用する全てのものは TextRepresentable によって強制される要件を全て満たさねばならず、また PrettyTextRepresentable によって強制される追加要件を満たさねばなりません。この例では、 PrettyTextRepresentableString を返す prettyTextualDescription という取得可能なプロパティを提供するための一つの要件を追加します。


SnakesAndLadders クラスは PrettyTextRepresentable を採用し、準拠するように拡張できます:


  1. extension SnakesAndLadders: PrettyTextRepresentable {
  2.         var prettyTextualDescription: String {
  3.                 var output = textualDescription + ":\n"
  4.                 for index in 1...finalSquare {
  5.                 switch board[index] {
  6.                 case let ladder where ladder > 0:
  7.                         output += "▲ "
  8.                 case let snake where snake < 0:
  9.                         output += "▼ "
  10.                 default:
  11.                         output += "○ "
  12.                 }
  13.                 }
  14.                 return output
  15.         }
  16. }


この機能拡張 (extension) は、それが PrettyTextRepresentable プロトコルを採用し、SnakesAndLadders 型のため prettyTextualDescription プロパティの実装を提供することを述べています。PrettyTextRepresentable である全てのものは TextRepresentable でもなければならず、それで prettyTextualDescription の実装は、出力文字列を開始する TextRepresentable プロトコルから textualDescription プロパティにアクセスすることによって開始します。これは、コロンと改行を付加し、そのかなりなテキスト表現の開始としてこれを使用しています。その後、ボードの正方形の配列を反復処理し、各正方形の内容を表現する幾何学的な形を追加します:


prettyTexualDescription プロパティは、今やあらゆる SnakesAndLadder インスタンスのかなりなテキストの説明を印刷するために使用できます。


  1. print(game.prettyTextualDescription)
  2. // A game of Snakes and Ladders with 25 squares:
  3. // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○


クラス専用プロトコル


プロトコルの継承リストに、AnyObject を追加することによって、プロトコルの採用をクラス型 (構造体または列挙型ではない) に限定することができます。


  1. protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
  2.         // class-only protocol definition goes here
  3. }


上記の例では、SomeClassOnlyProtocol はクラス型によってのみ採用できます。SomeClassOnlyProtocol を採用しようとして構造体や列挙型の定義を書くと、コンパイル時エラーになります。


注意: そのプロトコルの要件によって定義された動作が、準拠型が値の意味ではなく、参照の意味を持つことを前提としまたは必要とするとき、クラス専用のプロトコルを使用してください。参照と値の意味の詳細については、構造体と列挙型は値型 と、クラスは参照型 を参照して下さい。


プロトコルの構成


一度に複数のプロトコルに準拠する型を要求するのが便利な事があります。プロトコルの構成 で一つの要件に複数のプロトコルを組み合わせることができます。プロトコルの構成は、構成内のすべてのプロトコルの要件を組み合わせた一時的なローカルプロトコルを定義したかのように動作します。プロトコル構成は、新しいプロトコル型を定義しません。


プロトコルの構成は、someprotocol & AnotherProtocol の形です。アンパサンド(&) で区切って必要なだけ多くのプロトコルをリストできます。プロトコルのそのリストに加えて、プロトコル構成には 1 つのクラス型を含めることもでき、これを使用して必須スーパークラスを指定することができます。


ここで関数パラメータ上の一つのプロトコル構成要件に NamedAged という2つのプロトコルを組み合わせた例を示します。


  1. protocol Named {
  2.         var name: String { get }
  3. }
  4. protocol Aged {
  5.         var age: Int { get }
  6. }
  7. struct Person: Named, Aged {
  8.         var name: String
  9.         var age: Int
  10. }
  11. func wishHappyBirthday(to celebrator: Named & Aged) {
  12.         print("Happy birthday \(celebrator.name) , you're \(celebrator.age)!")
  13. }
  14. let birthdayPerson = Person(name: "Malcolm", age: 21)
  15. wishHappyBirthday(to: birthdayPerson)
  16. // prints "Happy birthday Malcolm, you're 21!"


この例では、取得可能な String プロパティの name と言う一つの要件を持つ、Named プロトコルがあります。取得可能な Int 型プロパティの age と言う一つの要件がある、Aged プロトコルもあります。これらのプロトコルの両方が Person と言う構造体によって採用されています。


また、この例では、wishHappyBirthday(to:) 関数も定義しています。celebrstor パラメータの型は、Named & Aged であり、これは、"NamedAged プロトコルの両方に準拠するすべての型" を意味します。必須プロトコルの両方に適合している限り、どの特定の型が関数に渡されたかは関係ありません。


この例は次に、birthdayPerson という新しい Person インスタンスを作成し、この新しいインスタンスを wishHappyBirthday(to:) 関数に渡します。Person は両方のプロトコルに準拠しているので、この呼び出しは有効で、wishHappyBirthday(to:) 関数はその誕生日の挨拶を印刷できます。


以前の例の Named プロトコルと Location クラスを組み合わせた例を次に示します。


  1. class Location {
  2.         var latitude: Double
  3.         var longitude: Double
  4.         init(latitude: Double, longitude: Double) {
  5.                 self.latitude = latitude
  6.                 self.longitude = longitude
  7.         }
  8. }
  9. class City: Location, Named {
  10.         var name: String
  11.         init(name: String, latitude: Double, longitude: Double) {
  12.                 self.name = name
  13.                 super.init(latitude: latitude, longitude: longitude)
  14.         }
  15. }
  16. func beginConcert(in location: Location & Named) {
  17.         print("Hello, \(location.name)!")
  18. }
  19. let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)
  20. beginConcert(in: seattle)
  21. // Prints "Hello, Seattle!"


beginConcert(in:) 関数は Location & Named 型のパラメータをとります。これは "Location のサブクラスで Named プロトコルに準拠するすべての型" を意味します。この場合には、City は両方の要件を満たします。


PersonLocation のサブクラスではないため、birthdayPersonbeginConcert(in:) 関数に渡すことは無効です。同様に、Named プロトコルに準拠していない Location のサブクラスを作成した場合、その型のインスタンスを使用して beginConcert(in:) を呼び出すことも無効です。


プロトコル準拠の確認


型キャスト で説明したように isas 演算子を、プロトコルの準拠をチェックするため、また特定のプロトコルにキャストするため使用できます。プロトコルへのキャストのチェックは、型のチェックとキャストとまったく同じ構文に従います。


この例では、取得可能な area と言う Double の一つのプロパティ要件を持つ HasArea と言うプロトコルを定義しています。


  1. protocol HasArea {
  2.         var area: Double { get }
  3. }


ここに2つのクラス、CircleCountry があり、両方とも HasArea プロトコルに準拠しています


  1. class Circle: HasArea {
  2.         let pi = 3.1415927
  3.         var radius: Double
  4.         var area: Double { return pi * radius * radius }
  5.         init(radius: Double) { self.radius = radius }
  6. }
  7. class Country: HasArea {
  8.                 var area: Double
  9.         init(area: Double) { self.area = area }
  10. }


Circle クラスは、格納された radius プロパティに基づいて、計算されたプロパティとして area プロパティの要件を実装しています。Country クラスは格納されたプロパティとして直接 area の要件を実装しています。どちらのクラスも正しく HasArea プロトコルに準拠しています。


ここで、HasArea プロトコルに準拠していない、 Animal と言うクラスがあります。


  1. class Animal {
  2.         var legs: Int
  3.         init(legs: Int) { self.legs = legs }
  4. }


CircleCountryAnimal クラスは、共有する基本のクラスを持っていません。それにもかかわらず、それらはすべてクラスであり、そして3つ全ての型のインスタンスは、型 AnyObject の値を格納する配列を初期化するために使えます:


  1. let objects: [AnyObject] = [
  2.         Circle(radius: 2.0),
  3.         Country(area: 243_610),
  4.         Animal(legs: 4)
  5. ]


objects 配列は、2ユニットの半径の Circle インスタンスを含む配列リテラルで初期化されます。Country インスタンスは、平方キロメートルで表したイギリスの表面積で初期化されます。そして Animal インスタンスは、4つの足で初期化されます。


objects 配列は、反復処理することができるようになり、配列内の各オブジェクトは、それが HasArea プロトコルに準拠するかどうかを確認できます。


  1. for object in objects {
  2.         if let objectWithArea = object as? HasArea {
  3.                 print("Area is \(objectWithArea.area)")
  4.         } else {
  5.                 print("Something that doesn't have an area")
  6.         }
  7. }
  8. // Area is 12.5663708
  9. // Area is 243610.0
  10. // Something that doesn't have an area


配列内のオブジェクトが HasArea プロトコルに準拠している時はいつでも、optional の値は、as? 演算子が objectWithArea と言う定数に optional に結合して開封され返ります。objectWithArea 定数は HasArea 型であることが知られており、したがって、その area プロパティには、アクセスでき、安全な型方法で印刷できます。


基礎となるオブジェクトは、キャストするプロセスによっては変更されないことに注意してください。それらは、CircleCountryAnimal であり続けます。しかし、それらが objectWithArea 定数に格納された時点で、それらは HasArea 型であるとのみ知られるので、それらの area プロパティのみにアクセスできます。



Optional のプロトコル要件


プロトコルには optional の要件 を定義できます。これらの要件は、プロトコルに準拠する型で実装する必要はありません。optional の要件は、プロトコルの定義の一部として、optional の修飾子を前に付けます。optional の要件は、Objective-C と相互運用するコードを書けるように、利用できます。プロトコルおよび optional の要件は両方とも @objc 属性でマークされなければなりません。その @objc プロトコルは、Objective-C のクラスや他の @objc クラスから継承するクラスのみに採用されることに注意してください。これらは、構造体または列挙型によっては採用できません。


optional の要件にメソッドやプロパティを使用する場合、その型は自動的に、optional になります。例えば、型メソッド(Int) -> String((Int) -> Strng)? になります。メソッドの戻り値ではなく、関数全体の型が optional に包まれていることに注意してください。


要件がプロトコルに準拠した型によって実装されなかった可能性を考慮して、optional のプロトコル要件は optional の連鎖で呼び出すことができます。someOptionalMethod?(someArgument) のように、呼び出されたときにメソッドの名前の後に疑問符を書き込むことによって、optional のメソッドの実装を確認してください。optional の連鎖の詳細については、Optional の連鎖 を参照してください。


以下の例では、その増分量を提供するために外部データソースを使用する Counter と言う整数をカウントするクラスを定義します。このデータソースは2つの optional の要件である CounterDataSource プロトコルによって定義されます。


  1. @objc protocol CounterDataSource {
  2.         @objc optional func incrementForCount(forCount count: Int) -> Int
  3.         @objc optional var fixedIncrement: Int { get }
  4. }


訳注: これらの @objc のついたソースをコンパイラに通すには、前もって import Foundation と書く必要があるようです。


CounterDataSource プロトコルは increment(ForCount:) と言う optional のメソッド要件と fixedIncrement と言う optional のプロパティの要件を定義しています。これらの要件は、Counter インスタンスの適切な増分量を提供するために、データ·ソースの2つの異なる方法を定義しています。



注意: 厳密に言えば、プロトコル要件の いずれ をも実装することなく CounterDataSource に準拠したカスタムクラスを書くことができます。それらは結局、両方とも optional です。技術的には許可されていますが、これは非常に良いデータソースとは言えません。


以下に定義された Counter クラスには、CounterDataSource? 型の optional の dataSource プロパティがあります:


  1. class Counter {
  2.         var count = 0
  3.         var dataSource: CounterDataSource?
  4.         func increment() {
  5.                 if let amount = dataSource?.increment? (forCount: count) {
  6.                         count += amount
  7.                 } else if let amount = dataSource?.fixedIncrement {
  8.                         count += amount
  9.                 }
  10.         }
  11. }


Counter クラスは、count と言う変数プロパティに現在の値を格納します。Counter クラスは、また increment と言うメソッドも定義しており、そのメソッドが呼び出されるたびに count プロパティを増分します。


increment() メソッドは、まずそのデータソースに increment(forCount:) メソッドの実装を探して増分量を取得しようとします。increment() メソッドは increment(forCount:) を呼び出そうとして、optional の連鎖を使用し、メソッドの一つの引数として現在の count 値を渡します。


ここで演じる optional の連鎖の 2つの レベルに注意してください。第一に、dataSourcenil である可能性があり、したがって dataSourcenil でない場合にのみ increment(forCount:) を呼び出す必要があることを示すために、dataSource はその名前の後に疑問符があります。第二に、 dataSource存在し ても、それは optional の要件なので、increment(forCount:) を実装していることを保証するものではありません。ここで、increment(forCount:) が実装されていない可能性は、optional の連鎖によって処理されます。increment(forCount:) への呼び出しは increment(forCount:) が存在する時にのみ起こり、すなわちそれが nil でない場合にのみ起こります。increment(forCount:) も、その名前の後に疑問符が書かれているのはこのためです。


increment(forCount:) への呼び出しは、これらの2つの理由のいずれかで失敗する可能性があるため、呼び出しは、optionalInt 値を返します。これは increment(forCount:)CounterDataSource の定義で optional でない Int 値を返すように定義されていても同様です。2つの optional の連鎖の操作が、次々とあっても、結果はまだ一つの optional で包み込まれています。複数の optional の連鎖の操作の使用については、連鎖の複数レベルのリンク を参照して下さい。


increment(forCount:) を呼び出した後、それが返す optional の Int は、optional の結合を使用して、amount と言う定数に開封されます。optional の Int に値がある場合、すなわち、デリゲートとメソッドの両方が存在し、そしてメソッドが値を返す場合、開封された amount は格納された count プロパティに追加され、そして増分は完了します。


increment(forCount:) メソッドから値を取得でき ない 場合、dataSourcenil か、またはデータソースが increment(forCount:) を実装していないためのいずれかであり、その後代わりに increment() メソッドが、データ·ソースの fixedIncrement プロパティから値を取得しようとします。fixedIncrement プロパティも optional の要件であり、したがって、その値も CounterDataSource プロトコル定義の一部として fixedIncrement が optional でない Int プロパティとして定義されているにもかかわらず、optional の Int 値です。


ここで、データソースが、それが照会されるたびに定数の 3 の値を返す単純な CounterDataSource を実装しましょう。optional の fixedIncrement プロパティの要件を実装することでこれを行います:


  1. class ThreeSource: NSObject, CounterDataSource {
  2.         let fixedIncrement = 3
  3. }


新しい Counter インスタンスのデータソースとして ThreeSource のインスタンスを使用できます。


  1. var counter = Counter()
  2. counter.dataSource = ThreeSource()
  3. for _ in 1...4 {
  4.         counter.increment()
  5.         print(counter.count)
  6. }
  7. // 3
  8. // 6
  9. // 9
  10. // 12


上記のコードは新しい Counter インスタンスを作成します。そのデータソースを新しい ThreeSource インスタンスに設定します。そして counter の increment() メソッドを4回呼び出します。予想されるように、3回 increment() が呼ばれ、counter の count プロパティが増加します。


ここで TowardsZeroSource と言う、より複雑なデータソースがあり、これは Counter インスタンスを現在の count 値からゼロに向かってカウントダウンまたはアップします。


  1. class TowardsZeroSource: NSObject, CounterDataSource {
  2.         func increment(forCount count: Int) -> Int {
  3.                 if count == 0 {
  4.                         return 0
  5.                 } else if count < 0 {
  6.                         return 1
  7.                 } else {
  8.                         return -1
  9.                 }
  10.         }
  11. }


TowardsZeroSource クラスは、CounterDataSource プロトコルから、optional の increment(forCount:) メソッドを実装し、どの方向にカウントが行われるかを示すために count 引数を使います。もし count がすでにゼロなら、メソッドは更なるカウントが起こらない事を示すために 0 を返します。


-4 からカウントをゼロにするために、既存の Counter インスタンスで TowardsZeroSource のインスタンスを使用できます。カウンタがゼロに達すると、それ以上のカウントは行われません。


  1. counter.count = -4
  2. counter.dataSource = TowardsZeroSource()
  3. for _ in 1...5 {
  4. counter.increment()
  5. print(counter.count)
  6. }
  7. // -3
  8. // -2
  9. // -1
  10. // 0
  11. // 0


プロトコル拡張機能


プロトコルは適合する型にメソッドとプロパティの実装を提供するために拡張することができます。これは、各型の個別の適合性やグローバル関数でよりも、プロトコル自身で動作を定義できます。


例えば、RandomNumberGenerator プロトコルは、randomBool() メソッドを提供するように拡張でき、ランダムな Bool 値を返すために必要な randm() メソッドの結果を使用します。


  1. extension RandomNumberGenerator {
  2.         func randomBool() -> Bool {
  3.                 return random() > 0.5
  4.         }
  5. }


プロトコル上の拡張機能を作成することにより、すべての適合型が何も追加の変更なしに、このメソッドの実装を自動的に得ることができます。


  1. let generator = LinearCongruentialGenerator()
  2. print("Here's a random number: \(generator.random())")
  3. // Prints "Here's a random number: 0.37464991998171"
  4. print("And here's a random Boolean: \(generator.randomBool())")
  5. // Prints "And here's a random Boolean: true"

デフォルトの実装の提供


そのプロトコルの全てのメソッドまたは計算されたプロパティ要件に、デフォルトの実装を提供するために、プロトコルの拡張機能を使用できます。準拠する型が、必要なメソッドやプロパティの独自の実装を提供している場合、その実装は、拡張機能が提供するものの代わりに使用されます。


注意: 拡張機能によって提供されるデフォルトの実装とプロトコル要件は、optional のプロトコル要件とは区別されます。準拠する型はいずれかの独自の実装を提供する必要はあなく、デフォルトの実装の要件は、optional の連鎖なしで呼び出すことができます。


例えば、PrettyTextRepresentable プロトコルは、その必須 prettyTextualDescription プロパティのデフォルトの実装を提供できる TextRepresentable プロトコルを継承しており、単に textualDescription プロパティにアクセスした結果を返します:


  1. extension PrettyTextRepresentable {
  2.         var prettyTextualDescription: String {
  3.                 return textualDescription
  4.         }
  5. }


プロトコル拡張機能に制約を追加


プロトコル拡張機能を定義するときは、拡張機能のメソッドとプロパティが利用可能になる前に、準拠した型が満たさなければならない制約を指定できます。汎用の Where 句 で説明したように、汎用の where 句を使用して、拡張しようとしているプロトコルの名前の後に、これらの制約を記述します。


たとえば、その要素が上記の例から TextRepresentable プロトコルに準拠する全てのコレクションに適用される Collection プロトコルへの拡張機能を定義できます。


  1. extension Collection where Iterator.Element: TextRepresentable {
  2.         var textualDescription: String {
  3.                 let itemsAsText = self.map { $0.textualDescription }
  4.                 return "[" + itemsAsText.joined(separator: ", ") + "]"
  5.         }
  6. }


textualDescription プロパティは括弧で囲まれたカンマ区切りのリストの中に、コレクション内の各要素のテキスト表現を連結することによって、コレクション全体のテキスト記述を返します。


TextRepresentable プロトコルに準拠する、前の例から Hamster 構造体、および Hamster 値の配列を考えてみましょう:


  1. let murrayTheHamster = Hamster(name: "Murray")
  2. let morganTheHamster = Hamster(name: "Morgan")
  3. let mauriceTheHamster = Hamster(name: "Maurice")
  4. let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]


ArrayCollection に準拠しており、配列の要素が TextRepresentable プロトコルに準拠しているため、配列はその内容のテキスト表現を取得するために textualDescription プロパティを使用できます。


  1. print(hamsters.textualDescription)
  2. // Prints "[A hamster named Murray, A hamster named Morgan, A hamster named Maurice]"

注意: 準拠する型が同じメソッドまたはプロパティの実装を提供する複数の制約された拡張機能の要件を満たしている場合、Swift は、最も特殊な制約に対応した実装を使用します。





前:機能拡張 次:ジェネリック(汎用)
目次
Xcode 10 の新機能

Swift:はじめに
Swift と Cocoa と Objective-C
Swift Blog より

  • ようこそ Swift へ(Part I)
  • Swift について
  • バージョン互換性
  • Swift のツアー
  • 単純な値
    制御フロー
    関数とクロージャ
    オブジェクトとクラス
    列挙型と構造体
    プロトコルと拡張機能
    エラー処理
    汎用(ジェネリック)
  • Swift 言語のガイド(Part II)
  • Swift の基本
  • 定数と変数
  • 定数と変数の宣言
    型注釈
    定数と変数の命名
    定数と変数の印刷
    コメント
    セミコロン
  • 整数
  • 整数の境界
    Int
    UInt
    浮動小数点数
    安全な型と型推論
    数値リテラル
  • 数値型変換
  • 整数変換
    整数と浮動小数点間の変換
    型エイリアス
    ブール型
    タプル
  • Optional
  • nil
    if 文と強制開封
    Optional の結合
    暗黙に開封された Optionals
    エラー処理
  • アサーション(断言)と前提条件
  • アサーションを使用したデバッグ
    前提条件の実施
  • 基本演算子
  • 専門用語
    代入演算子
  • 算術演算子
  • 剰余演算子
    単項マイナス演算子
    単項プラス演算子
    複合代入演算子
    比較演算子
    三項条件演算子
    Nil 合体演算子
  • 範囲演算子
  • 閉鎖範囲演算子
    半開放範囲演算子
    片方の範囲
  • 論理演算子
  • 論理 NOT 演算子
    論理 AND 演算子
    論理 OR 演算子
    論理演算子の組み合わせ
    明示的な括弧
  • 文字列と文字
  • 文字列リテラル
    複数行の文字列リテラル
    文字列リテラル内の特殊文字
    空の文字列の初期化
    文字列の可変性
    文字列は値の型
    文字を使った作業
    文字列と文字を連結
    文字列補間
  • ユニコード(Unicode)
  • Unicode スカラー
    文字列リテラルの中の特別の文字
    拡張書記クラスタ
    文字を数える
  • 文字列のアクセスと変更
  • 文字列のインデックス
    部分文字列
    挿入と削除
  • 文字列の比較
  • 文字列と文字の等価性
    接頭辞と接尾辞の等価性
  • 文字列の Unicode 表現
  • UTF-8 の表現
    UTF-16 表現
    Unicode のスカラー表現
  • コレクション型
  • コレクションの可変性
  • 配列
  • 配列型省略構文
    空の配列の作成
    デフォルト値を持つ配列の作成
    2つの配列を共にして一つの配列に
    配列リテラルでの配列の作成
    配列へのアクセスと変更
    配列の繰り返し処理
  • セット
  • セット型のハッシュ値
    セット型の構文
    空のセットの作成と初期化
    配列リテラルでセットの作成
    セットへのアクセスと変更
    セットを反復処理
  • セット操作の実行
  • 基本的なセットの操作
    セットの身分と等価性
  • Dictionary
  • Dictionary 型の省略型構文
    空の Dictionary を作成
    Dictionary リテラルで Dictionary の作成
    Dictionary のアクセスと変更
    Dictionary を繰り返し処理
  • フロー制御
  • For-In ループ
  • While ループ
  • While
    Repeat-While
  • 条件文
  • if 文
  • Switch
  • 暗黙の Fallthrough なし
    範囲の一致
    タプル(Tuples)
    値の結合
    Where
    複合した case
  • 制御転送文
  • Continue
  • Break
  • ループ文内の Break
    Switch 文内の Break
    Fallthrough
    ラベル付きの文
    早期終了
    API 利用可能性の確認
  • 関数
  • 関数の定義と呼び出し
  • 関数のパラメータと戻り値
  • パラメータなしの関数
    複数パラメータの関数
    戻り値なしの関数
    複数の戻り値を持つ関数
    optional のタプル型の戻り値
  • 関数引数のラベルとパラメータ名
  • 引数のラベルの指定
    引数ラベルの省略
    デフォルトのパラメータ値
    可変個引数のパラメータ
    In-Out パラメータ
  • 関数型
  • 関数型の使用
    パラメータ型としての関数型
    戻り値の型としての関数型
    入れ子になった関数
  • クロージャ
  • クロージャ式
  • ソートするメソッド
    クロージャ式の構文
    文脈から型を推論
    単一式クロージャからの暗黙的戻り値
    引数名の省略
    演算子メソッド
    後続クロージャ
    値のキャプチャ
    クロージャは参照型
    クロージャのエスケープ
    オートクロージャ
  • 列挙型
  • 列挙型の構文
    switch 文で列挙型の値の一致
    関連する値
  • 生の値
  • 暗黙に割り当てられた生の値
    生の値からの初期化
    再帰的な列挙型
  • クラスと構造体
  • クラスと構造体を比較
  • 定義の構文
    クラスと構造体のインスタンス
    プロパティにアクセス
    構造体型のためのメンバー化イニシャライザ
    構造体と列挙型は値型
  • クラスは参照型
  • ID 演算子
    ポインタ
    クラスと構造体の間の選択
    文字列、配列、辞書の代入とコピーの動作
  • プロパティ
  • 格納されたプロパティ
  • 定数構造体インスタンスの格納されたプロパティ
    遅延した格納されたプロパティ
    格納されたプロパティとインスタンス変数
  • 計算されたプロパティ
  • セッタ宣言の省略形
    読み取り専用の計算されたプロパティ
    プロパティ監視者
    グローバルとローカル変数
  • 型プロパティ
  • 型プロパティの構文
    型プロパティの照会と設定
  • メソッド
  • インスタンスメソッド
  • self プロパティ
    インスタンスメソッド内から値の型を変更
    変異メソッド内で self に代入
    型メソッド
  • サブスクリプト
  • サブスクリプトの構文
    サブスクリプトの使用法
    サブスクリプトのオプション
  • 継承
  • 基本クラスの定義
    サブクラス化
  • オーバーライド(上書き)
  • スーパークラスメソッド、プロパティ、サブスクリプトへのアクセス
    オーバーライドするメソッド
  • オーバーライドするプロパティ
  • プロパティのゲッタとセッタのオーバーライド
    プロパティ監視者のオーバーライド
    オーバーライドの防止
  • 初期化
  • 格納されたプロパティの初期値を設定
  • イニシャライザ
    デフォルトのプロパティ値
  • 初期化のカスタマイズ
  • 初期化パラメータ
    パラメータ名と引数ラベル
    引数ラベルのないイニシャライザのパラメータ
    Optional のプロパティ型
    初期化中に定数プロパティへの代入
  • デフォルトのイニシャライザ
  • 構造体型のためのメンバ化イニシャライザ
    値型のイニシャライザデリゲート
  • クラスの継承と初期化
  • 指定イニシャライザとコンビニエンスイニシャライザ
    指定とコンビニエンスイニシャライザの構文
    クラス型のイニシャライザデリゲート
    二相の初期化
    イニシャライザ継承とオーバーライド
    自動イニシャライザの継承
    実際の指定とコンビニエンスイニシャライザ
  • 失敗可能イニシャライザ
  • 生の値を持つ列挙型のための失敗可能イニシャライザ
    初期化失敗の伝播
    失敗可能イニシャライザのオーバーライド
    init! の失敗可能イニシャライザ
    必須イニシャライザ
    クロージャや関数でのデフォルトのプロパティ値設定
  • デイニシャライザ
  • デイニシャライザはどのように働くか
    作動中のデイニシャライザ
  • Optional の連鎖
  • 強制開封の代替としての Optional の連鎖
    Optional の連鎖のモデルクラスの定義
    Optional の連鎖を使用したプロパティへのアクセス
    Optional の連鎖を通じてメソッドを呼び出す
  • Optional の連鎖を通じてサブスクリプトへのアクセス
  • Optional 型のサブスクリプトにアクセス
    連鎖の複数レベルのリンク
    optional の戻り値を持つメソッドでの連鎖
  • エラー処理
  • エラーの表現と Throw
    エラーの処理
    throw 関数を使用したエラーの伝播
    Do-Catch を使用したエラー処理
    エラー をOptional の値に変換
    エラー伝播を無効に
    クリーンアップアクションの指定
  • 型キャスト
  • 型キャストのためのクラス階層の定義
    型のチェック
    ダウンキャスト
  • Any と AnyObjecgt 用の型キャスティング
  • ネストした型
  • 実際のネストした型
    ネストした型への参照
  • 拡張機能
  • 拡張機能の構文
    計算されたプロパティ
    イニシャライザ
  • メソッド
  • 変異インスタンスメソッド
    サブスクリプト
    ネストした型
  • プロトコル
  • プロトコルの構文
    プロパティの要件
    メソッドの要件
    変異メソッドの要件
  • イニシャライザの要件
  • プロトコルイニシャライザ要件のクラス実装
    失敗可能イニシャライザの要件
    型としてのプロトコル
    デリゲート
  • 拡張機能を持つプロトコル準拠の追加
  • 拡張機能を持つプロトコルの採用を宣言
    プロトコル型のコレクション
    プロトコルの継承
    クラス専用プロトコル
    プロトコルの構成
    プロトコル準拠の確認
    Optional のプロトコル要件
  • プロトコル拡張機能
  • デフォルトの実装の提供
    プロトコル拡張機能に制約を追加
  • ジェネリック(汎用)
  • 汎用が解決する問題
    汎用関数
    型パラメータ
    型パラメータの命名
    汎用の型
    汎用型の拡張
  • 型の制約
  • 型制約の構文
    実際の型の制約
  • 関連型
  • 実際の関連型
    既存の型を拡張して関連型を指定
    型注釈を使用して関連型を制約
    汎用の Where 句
    汎用の Where 句を含む拡張機能
    関連する型と汎用の Where 句
    汎用のサブスクリプト
  • 自動参照カウント
  • どのように ARC は働くか
    実際の ARC
    クラスインスタンス間の強い循環参照
  • クラスインスタンス間の強い循環参照の解決
  • 弱い参照
    所有されていない参照
    所有されていない参照と暗黙に開封された Optional のプロパティ
    クロージャの strong な循環参照
  • クロージャの strong な循環参照の解決
  • キャプチャリストの定義
    弱い参照と所有されていない参照
  • メモリの安全性
  • メモリへのアクセス競合の理解
    メモリアクセスの特徴
    In-Out パラメータへのアクセスの競合
    メソッド内の Self へのアクセスの競合
    プロパティへのアクセスの競合
  • アクセス制御
  • モジュールとソースファイル
  • アクセスレベル
  • アクセスレベルの全体的指針
    デフォルトのアクセスレベル
    ターゲット一つのアプリのアクセスレベル
    フレームワークのアクセスレベル
    ユニットテストのターゲット用のアクセスレベル
    アクセス制御の構文
  • カスタム型
  • タプル型
    関数型
  • 列挙型
  • 生の値と関連する値
    ネストした型
    サブクラス化
  • 定数、変数、プロパティ、およびサブスクリプト
  • ゲッタとセッタ
  • イニシャライザ
  • デフォルトのイニシャライザ
    構造体型用のデフォルトメンバ化イニシャライザ
  • プロトコル
  • プロトコルの継承
    プロトコルの準拠
  • 拡張機能
  • 拡張機能の private メンバ
    汎用
    型エイリアス
  • 高度な演算子
  • ビット単位演算子
  • ビット単位の NOT 演算子
    ビット単位の AND 演算子
    ビット単位の OR 演算子
    ビット単位の XOR 演算子
  • ビット単位の左と右シフト演算子
  • 符号なし整数のシフト動作
    符号付き整数のシフト動作
  • オーバーフロー演算子
  • 値オーバーフロー
    優先順位と結合性
  • 演算子メソッド
  • 接頭辞と接尾辞演算子
    複合代入演算子
    等価演算子
  • カスタム演算子
  • カスタム挿入辞演算子の優先順位
  • 言語のガイド(Part III)
  • 言語リファレンスについて
  • 文法の読み方
  • 語彙の構造
  • 空白とコメント
    識別子
    キーワードと句読点
  • リテラル
  • 整数リテラル
    浮動小数点リテラル
    文字列のリテラル
    演算子

  • 型注釈
    型識別子
    タプル型
    関数型
    エスケープしないクロージャの制限事項
    配列型
    辞書型
    Optional の型
    暗黙に開封された Optional の型
    プロトコル構成の型
    メタタイプ型
    型の継承句
    型の推測

  • 接頭辞式
    Try 演算子
  • 二項式
  • 代入演算子
    三項条件演算子
    型キャスト演算子
  • 一次式
  • リテラル式
    Self 式
    スーパークラス式
  • クロージャ式
  • キャプチャ・リスト
    暗黙のメンバ式
    括弧で囲まれた式
    タプル式
    ワイルドカード式
    キーパス式
    セレクタ式
    キーパス文字列式
  • 接尾辞の式
  • 関数呼び出し式
    イニシャライザ式
    明示的なメンバ式
    接尾辞の Self 式
    サブスクリプト 式
    強制値の式
    Optional の連鎖式

  • ループ文
  • For-In 文
    While 文
    Repeat-While 文
  • 分岐文
  • if 文
    Guard 文
  • switch 文
  • switch 文は、網羅的である必要あり
    実行が暗黙的に case を Fall Through しない
    ラベル付き文
  • 制御転送文
  • break 文
    continue 文
    fallthrough 文
    return 文
    throw 文
    defer 文
    do 文
  • コンパイラ制御文
  • 条件コンパイルブロック
    行制御文
    利用可能条件
  • 宣言
  • トップレベルのコード
    コードブロック
    Import 宣言
    ­定数の宣言
  • 変数の宣言
  • 格納された変数と格納された変数のプロパティ
    計算された変数と計算されたプロパティ
    格納された変数監視者とプロパティの監視者
    型変数プロパティ
    型エイリアス宣言
  • 関数の宣言
  • パラメータ名
    In-Out パラメータ
    パラメータの特殊な種類
    メソッドの特殊な種類
    Throw する関数とメソッド
    Rethrow する関数とメソッド
    決して返さない関数
  • 列挙型の宣言
  • 任意の型の case を列挙
  • 間接による列挙
    生の値型の case を列挙
    列挙型 case へのアクセス
    構造体の宣言
    クラスの宣言
  • プロトコルの宣言
  • プロトコル・プロパティ宣言
    プロトコル・メソッド宣言
    プロトコル・イニシャライザ宣言
    プロトコル・サブスクリプト宣言
    プロトコルに関連した型の宣言
  • イニシャライザ宣言
  • 失敗可能イニシャライザ
    デイニシャライザ宣言
    拡張機能の宣言
    サブスクリプト宣言
    演算子の宣言
    優先順位グループ宣言
  • 宣言修飾子
  • アクセス制御レベル
  • 属性
  • 宣言の属性
  • インターフェイスビルダーで使われる宣言属性
    型の属性
  • パターン
  • ワイルドカードパターン
    識別子パターン
    値結合パターン
    タプルパターン
    列挙型 case パターン
    Optional のパターン
    型キャストパターン
    式のパターン
  • 汎用パラメータと引数
  • 汎用パラメータ句
  • 汎用の where 句
    汎用引数句
  • 文法のまとめ
  • 語彙の構造



    宣言
    属性
    パターン
    汎用パラメータと引数
  • マニュアルの変更履歴
  • 変更履歴












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)












    トップへ(Swift Language Basics)