是否有必要在协议上声明静态函数?使用协议的客户端必须在符合协议的类型上调用该函数吗?这打破了不必知道符合IMO协议的类型的想法。有没有办法以一种我不必知道符合我的协议的实际类型的方式调用协议上的静态函数?
答案 0 :(得分:24)
好问题。这是我谦虚的观点:
与在协议中声明的实例方法非常相似。
是的,与实例函数完全相同。
不。请查看以下代码:
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
老实说,我不知道为什么这是不可能的。
答案 1 :(得分:4)
是的,这是可能的:
Swift 3
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}
答案 2 :(得分:2)
感谢@appzYourLife的帮助!你的回答激发了我的答案。
@appzYourLife回答了我的问题。我有一个潜在的问题,我试图解决,以下代码解决了我的问题,所以我会在这里发布,也许它可以帮助有同样基本问题的人:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
答案 3 :(得分:1)
在这个派对上有点晚了。
这是我的解决方案"添加"使用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)
}
答案 4 :(得分:1)
我为此案例创建了另一个解决方案。恕我直言,这是非常干净和简单的。
首先,创建用于访问实例类型的协议。
protocol TypeAccessible {
func type() -> Self.Type
}
extension TypeAccessible {
func type() -> Self.Type {
return Swift.type(of: self)
}
}
然后在此处创建您的具体课程。关键是您的协议应符合TypeAccessible
协议。
protocol FooProtocol: TypeAccessible {
static func bar()
}
class Foo: FooProtocol {
static func bar() { }
}
在致电网站上将其用作
let instance: FooProtocol = Foo()
instance.type().bar()
对于其他用例,只需确保您的协议符合TypeAccessible
即可。
答案 5 :(得分:0)
使用Java接口等协议很少是个好主意。它们是元类型,用于定义合同,这是一种完全不同的东西。
话虽如此,仅仅为了理解,我找到了创建等效协议的静态工厂方法来编写自由函数的最简单有效的方法。
它应该包含协议的名称,希望这可以防止名称冲突,并提高可发现性。
在其他语言中,createP将是P的静态成员,名为create并被称为P.create(...),这将极大地提高可发现性并保证防止名称冲突。
但是,在swift中,这不是协议的选项,因此如果协议由于某种原因实际上真的用作接口的替代品,至少在函数名称中包含协议的名称是一个丑陋的解决方法,但仍然比没有好。
P.S。如果目标实际上是实现类似于带有结构的继承层次结构,那么联合样式枚举就是为此目的服务的工具:)
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
}
答案 6 :(得分:0)
这不是答案,而是问题的延伸。说我有:
@objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:@escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
我有一个管理各种类型的通用视图控制器(泛型类型是.fetchableObjectType ...基本上是NSFetchResult)。我需要检查特定对象类型是否符合协议,如果是,请调用它。
类似的东西:
// valid swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}
答案 7 :(得分:0)
我遇到一种情况,我需要根据DomainModel
个不同的响应来创建相同的2
对象。因此,这种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)