次のコード例があるとします。
_protocol MyProtocol {
func someFunction()
}
public class MyClass {
}
public extension MyClass: MyProtocol {
func someFunction() {
print("hello")
}
}
_
上記のコードをコンパイルすると、次のエラーが発生します。
エラー: 'public'修飾子は、プロトコルの適合を宣言する拡張機能では使用できません
拡張子をprivate
としてマークしても同じことが起こります。アクセスレベルの設定に関係なく、プロトコルに準拠した拡張機能のアクセスレベルを設定できないようです。プロトコル宣言をpublic
またはprivate
に設定しても、エラーは削除されません。
Swiftプロトコルに準拠している拡張機能のアクセスレベルをこのように制限する理由は何ですか?プロトコル準拠がクラスレベルで適用されている場合、そのような制限はありません。
コンパイラーに従ってprivate
/public
の指定を削除すると、someFunction()
のアクセスレベルはどうなりますか?
_extension MyClass: MyProtocol {
func someFunction() {
print("hello")
}
}
_
この場合、元のMyClass
の実装に従い、public
になると思いますが、よくわかりません。
拡張機能のプロトコル準拠はクラス全体がプロトコルに準拠することを意味し、拡張機能のアクセスレベルを再指定することは冗長であるため、この動作はありますか?
これは、プロトコル自体のアクセスレベル以外のアクセスレベルではプロトコルに準拠できないためです。つまり、public
プロトコルを使用している場合、private
に準拠することはできません。これは、プロトコルの適合性が実行時に照会できるものであるため(したがって、現在のモジュール間で異なることはなく、異なるファイル/モジュールで2回実装されることもあり)、また、タイプは1つのファイルのプロトコルに準拠し、他のファイルで使用された場合、そのプロトコルに準拠しませんでした。
someFunction
のアクセスレベルの質問については、他の関数と同じルールに従います。つまり、型自体のアクセスレベルが低い場合を除き、デフォルトはinternal
です。したがって、あなたの場合、MyClass
とMyProtocol
が両方ともpublic
である場合、someFunction()
にもpublic
をマークする必要があることを示すコンパイラエラーが表示されることが予想されます。ただし、MyProtocol
は実際にはinternal
のように見えるため、someFunction()
のデフォルトはinternal
になるため、アクセス修飾子を省略しても機能します。
プライベートな適合性は違反する可能性がありますLiskov Substitution Principle
Apple devloperフォーラムからの要約を同様の質問に返信して引用する:
「私がプライベートな適合について特に私が指摘した最大のことは、さらにサブクラス化されることを意図されたamonstクラスは、しばしば衝突する実装に終わることです。」
たとえば、プロトコルにプライベートに準拠し、そのすべてのメソッドを実装するクラスがあるとします。後でサブクラスがやって来て、同じことをしたいのですが、必要なメソッドを実装したいだけです(実装されていないオプションのものが、サブクラスが望むデフォルトの動作を提供する可能性があるためです)。しかし、今あなたは2つの問題を抱えています:
1)このプロトコルの実装を期待しているオブジェクトは、同じオブジェクト上でプロトコルの2つのコンシューマを持っている可能性があります。これにより、両方のオブジェクトが予期しない呼び出しから保護する必要があります。または、なし。プライベートな準拠のため、予期しない呼び出しを解決するためにサブクラスがスーパーを呼び出すことはできません。
2)スーパークラスの実装はその動作に影響を与えずに削除できないため、サブクラスがプロトコルを変更せずに必要な動作を取得する方法はありません。
コンパイラーに従ってプライベート/パブリック指定を削除すると、
someFunction()?
のアクセスレベルはどうなりますか?
あなたが言うことは何でも。 someFunction()
のアクセスレベルをマークすることを妨げるものは何もありません。ただし、この場合、MyProtocolのアクセスレベルはprivate
であるため、internal
としてマークすることはできません。
したがって、コードのデフォルトはinternal
です。デフォルトではpublic
はありません。 public
は常に明示的なオプトイン指定です。