プロトコルで静的関数を宣言するポイントはありますか?プロトコルを使用するクライアントは、とにかくプロトコルに準拠する型で関数を呼び出す必要がありますか?これは、プロトコルIMOに準拠するタイプを知る必要がないという考えを破ります。プロトコルに準拠する実際の型を知る必要がない方法で、プロトコルの静的関数を呼び出す方法はありますか?
いい質問ですね。これが私の謙虚な視点です。
プロトコルでインスタンスメソッドを宣言するのとほとんど同じです。
はい、インスタンス関数とまったく同じです。
いや。次のコードを見てください:
protocol Feline {
var name: String { get }
static func createRandomFeline() -> Feline
init()
}
extension Feline {
static func createRandomFeline() -> Feline {
return arc4random_uniform(2) > 0 ? Tiger() : Leopard()
}
}
class Tiger: Feline {
let name = "Tiger"
required init() {}
}
class Leopard: Feline {
let name = "Leopard"
required init() {}
}
let feline: Feline = arc4random_uniform(2) > 0 ? Tiger() : Leopard()
let anotherFeline = feline.dynamicType.createRandomFeline()
変数feline
内の実際の型がわかりません。 Feline
に準拠していることを知っています。ただし、静的プロトコルメソッドを呼び出しています。
プロトコルに準拠した値を作成せずに、プロトコルで宣言された静的メソッド/関数を呼び出したいと思います。
このようなもの:
Feline.createRandomFeline() // DANGER: compiler is not happy now
正直なところ、これが不可能な理由はわかりません。
はい、これは可能です:
Swift
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}
助けてくれてありがとう@appzYourLife!あなたの答えが私の答えに影響を与えました。
@appzYourLifeが私の質問に答えました。解決しようとしている根本的な問題があり、次のコードで問題を解決するので、ここに投稿します。同じ根本的な質問を持つ人に役立つかもしれません:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
今回のパーティーには少し遅れました。
typealias
を使用してプロトコルに静的プロパティ/関数/タイプを「追加」するための私のソリューションを次に示します。
例えば:
enum PropertyScope {
case all
case none
}
struct PropertyNotifications {
static var propertyDidChange =
Notification.Name("propertyDidChangeNotification")
}
protocol Property {
typealias Scope = PropertyScope
typealias Notifications = PropertyNotifications
var scope: Scope { get set }
}
次に、コードのどこでもこれを行うことができます:
func postNotification() {
let scope: Property.Scope = .all
NotificationCenter.post(name: Property.Notifications.propertyDidChange,
object: scope)
}
2
異なる応答から同じDomainModel
オブジェクトを作成する必要がある状況がありました。そのため、この(static
のprotocol
メソッドが役に立ちました)アプローチが助けになりました。
protocol BaseResponseKeyList: CodingKey {
static func getNameKey()->Self
}
enum FirstResponseKeyList: String, BaseResponseKeyList {
case name
func getNameKey()->FirstResponseKeyList {
return .name
}
}
enum SecondResponseKeyList: String, BaseResponseKeyList {
case userName
func getNameKey()->SecondResponseKeyList {
return .userName
}
}
struct MyDomainModel<T:BaseResponseKeyList> : Decodable {
var name:String?
required init(from d:Decoder) {
do {
let container = try d.container(keyedBy:T.self)
name = try container.decode(String.self, forKey:T.getNameKey())
}catch(_) {
print("error")
}
}
}
let myDomainModel = try JSONDecoder().decode(MyDomainModel <FirstResponseKeyList>.self, from: data)
let myDomainModel2 = try JSONDecoder().decode(MyDomainModel <SecondResponseKeyList>.self, from: data2)
Javaインターフェースのようなプロトコルを使用することはめったにありません。これらは完全に異なる種類のコントラクトを定義するためのメタタイプです。
そうは言っても、理解のためだけに、プロトコルの静的ファクトリメソッドに相当するものを作成して、自由な関数を記述する最も簡単で効果的な方法を見つけました。
名前の衝突を防ぎ、発見性を向上させることを期待して、プロトコルの名前を含める必要があります。
他の言語では、createPはcreateという名前のPの静的メンバーであり、P.create(...)として呼び出されます。これにより、検出可能性が大幅に向上し、名前の衝突を防ぐことができます。
ただし、Swiftでは、これはプロトコルのオプションではないため、プロトコルが何らかの理由で実際にインターフェイスの代替として実際に使用されている場合、少なくとも関数の名前にプロトコルの名前を含めることは、何もしないよりもわずかに良いい回避策です。
追伸実際に構造体を使用して継承階層のようなものを達成することが目標である場合、ユニオンスタイルの列挙型はその目的に役立つツールです:)
protocol P
{
var x: Int { get }
}
func createP() -> P
{
if (todayIsMonday())
{
return A()
}
else
{
return B()
}
}
class A: P
{
var x = 5
}
class B: P
{
var x = 7
}
これは質問の拡張であるため、答えではありません。私が持っていると言います:
@objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:@escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
そして、私はさまざまなタイプを管理する汎用View Controllerを持っています(一般的なタイプは.fetchableObjectType ...基本的にNSFetchResultです)。特定のオブジェクトタイプがプロトコルに準拠しているかどうかを確認し、準拠している場合はそれを呼び出します。
何かのようなもの:
// valid Swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid Swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}