プロトコルにオプショナル要件を定義することができます。この要件を、プロトコルに準拠する型で実装する必要はありません。オプショナル要件では、プロトコルの定義の一部として optional
を前に付けます。オプショナル要件でメソッドやプロパティを使用するとき、自動的にその型がオプショナルになります。例えば、(Int) -> String
型のメソッドは ((Int) -> String)?
になります。メソッドの戻り値だけでなく、関数型全体がオプショナルでラップされることに注目してください。
プロトコルに準拠する型で要件が実装されない可能性があるため、オプショナルプロトコル要件をオプショナルチェーンで呼び出すことができます。オプショナルメソッドを呼び出すとき、メソッドの名前の後に someOptionalMethod?(someArgument)
のようにクエスチョンマークを記述して、オプショナルメソッドの実装をチェックします。オプショナルチェーンの情報は、Optional Chaining を確認してください。
プロトコルに @objc
属性が付けられている場合、オプショナルプロトコル要件のみ指定することができます。
この属性は、プロトコルが Objective-C に露出していることを示し、『Using Swift with Cocoa and Objective-C (Swift 2.2)』で説明されています。Objectvie-C と相互運用しない場合であっても、オプショナル要件を指定したい場合には、プロトコルに @objc
属性を付ける必要があります。
また、Objective-C クラスや、他の @objc
クラスを継承するクラスのみ、プロトコルを採用することができることに注意してください。構造体や列挙型では採用できません。
以降の例では、整数をカウントするクラス Counter
を定義し、増加量を提供する外部のデータソースを使用します。このデータソースは CounterDataSource
プロトコルで定義され、オプショナル要件が 2 つあります。
@objc protocol CounterDataSource {
optional func incrementForCount(count: Int) -> Int
optional var fixedIncrement: Int { get }
}
CounterDataSource
プロトコルは、オプショナルメソッド要件 incrementForCount(_:)
とオプショナルプロパティ要件 fixedIncrement
を定義しています。これらの要件は、Counter
インスタンスに適切な増加量を提供するデータソースの 2 つの異なる手段を定義しています。
CounterDataSource
に準拠するクラスを記述することができます。それらの要件はともにオプショナルです。技術的には許容されますが、データソースとして役に立ちません。
次の Counter
クラスは、CounterDataSource?
型のオプショナルな dataSource
プロパティを定義しています。
class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.incrementForCount?(count) {
count += amount
} else if let amount = dataSource?.fixedIncrement {
count += amount
}
}
}
Counter
クラスは変数プロパティ count
に現在値を保持します。またh、Counter
クラスはメソッドが呼び出される度に count
プロパティを増加するメソッド increment
を定義しています。
increment()
メソッドは、はじめにデータソースの incrementForCount(_:)
メソッドの実装を探して増加量を取り出そうとします。increment()
メソッドは、incrementForCount(_:)
を呼び出すためにオプショナルチェーンを使用し、メソッドの引数として count
の現在値を渡します。
ここでは、オプショナルチェーンが 2 階層になっています。1 つ目は、dataSource
が nil
である可能性があるため、dataSource
が nil
でない場合にのみ incrementForCount(_:)
が呼び出されることを示すために、dataSource
の名前の後にクエスチョンマークを付けます。2 つ目は、detaSource
が存在している場合で、incrementForCount(_:)
がオプショナル要件であるため、実装されている保証がありません。ここでは、incrementForCount(_:)
が実装されていない可能性があり、これもまたオプショナルチェーンで扱われています。incrementForCount(_:)
が存在している、つまり nil
でない場合にのみ、incrementForCount(_:)
の呼び出しが起こります。このため、incrementForCount(_:)
もまた名前の後にクエスチョンマークを記述しています。
incrementForCall(_:)
の呼び出しがこれら 2 つのいずれかの理由で失敗する可能性があるため、呼び出しはオプショナルな Int
値を返します。これは、CounterDataSource
の定義でオプショナルでない Int
値を返すように incrementForCount(_:)
が定義されている場合でもそうなります。オプショナルチェーンの処理が続けて 2 つありますが、結果は 1 つのオプショナルでラップされます。複数のオプショナルチェーンの処理についての詳細な情報は、Linking Multiple Levels of Chaining を確認してください。
incrementForCount(_:)
を呼び出した後、返されるオプショナル Int
は、オプショナルバインディングで定数 amount
にアンラップされます。オプショナル Int
に値がある場合、つまりデリゲートとメソッドの両方が存在し、メソッドが値を返した場合、アンラップされた amount
はストアドプロパティの count
に追加され、増加処理が完了します。
dataSource
が nil
なため、あるいはデータソースが incrementForCount(_:)
を実装していないために incrementForCount(_:)
メソッドから値を取り出すことができない場合、increment()
メソッドは代わりにデータソースの fixedIncrement
プロパティから値を取り出そうとします。fixedIncrement
プロパティもまたオプショナル要件なため、CounterDataSource
プロトコル定義の一部として fixedIncrement
がオプショナルでない Int
プロパティとして定義されているとしても、その値はオプショナルな Int
値になります。
次は、常にデータソースが定数値 3
を返すシンプルな CounterDataSource
の実装です。fixedIncrement
オプショナルプロパティ要件を実装しています。
class ThreeSource: NSObject, CounterDataSource {
let fixedIncrement = 3
}
新しい Counter
インスタンスのデータソースとして、ThreeSource
のインスタンスを使用することができます。
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
counter.increment()
print(counter.count)
}
// 3
// 6
// 9
// 12
このコードは新しい Counter
インスタンスを生成し、新しい ThreeSource
インスタンスがそのデータソースになるように設定し、そしてカウンターの increment()
メソッドを 4 回呼び出しています。期待どおりに、increment()
が呼び出されるたびに、カウンターの count
プロパティが 3 増加しています。
次はより複雑なデータソース TowardsZeroSource
で、Counter
インスタンスが現在の count
値からゼロに向けて増加または減少させます。
@objc class TowardsZeroSource: NSObject, CounterDataSource {
func incrementForCount(count: Int) -> Int {
if count == 0 {
return 0
} else if count < 0 {
return 1
} else {
return -1
}
}
}
TowardsZeroSource
クラスは、CounterDataSource
プロトコルからオプショナルメソッド incrementForCount(_:)
を実装し、どちらの方向に計算するかを判定するために count
引数値を使用しています。count
がすでにゼロの場合、さらに計算が行われないようにメソッドは 0
を返します。
-4
からゼロまでカウントするために、既存の Counter
インスタンスに TowardsZeroSource
インスタンスを使用することができます。カウンターがゼロに達すると、それ以上は計算されません。
counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
counter.increment()
print(counter.count)
}
// -3
// -2
// -1
// 0
// 0
Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.