【问题标题】:Swift: Property conforming to a specific class and in the same time to multiple protocolsSwift:属性符合特定类,同时符合多个协议
【发布时间】:2014-09-10 13:47:46
【问题描述】:

在 Objective-C 中,可以这样写:

@property(retain) UIView<Protocol1, Protocol2, ...> *myView;

但是我怎样才能用 swift 编写这段代码呢?

我已经知道如何让一个属性符合许多协议,但是使用继承却不行:

var myView: ??? protocol<Protocol1, Protocol2, ...>

编辑:

我使用许多UIView 子类型,如UIImageView、UILabel 或其他,我需要使用一些UIView 属性以及协议中定义的一些方法。在最坏的情况下,我可以创建一个带有所需属性的UIViewProtocol,但我会知道是否可以在 Swift 中声明一个属性/变量,其类型和协议要符合。

【问题讨论】:

  • 我认为这不可能像您在 Objective-C 中那样。你能多谈谈协议吗?认为可能有一种更适合 Swift 的不同方法。
  • 我不明白为什么你会试图强制一个像 UIView 或 UILabel 这样的类来遵守一些它还没有遵守的协议,在这种情况下,没有必要指定它。您是否扩展这些类以符合新协议?
  • @TomErikStøwer 我认为这确实是最好的解决方案。我仍在学习 Swift,我会知道它是否可能像在 Objective-C 中一样。是的,我扩展它们以符合新协议,所以没有问题。
  • @GuidoHendriks 协议可以帮助我进行一些视图选择和拖放操作。就像我之前说的,我还在学习 Swift,所以我尝试用同样的方式学习新事物。
  • @YannickL。好的,我明白了,但是如果您已经在扩展这些类,那么从属性声明的角度来看,协议一致性不是隐含的吗?

标签: swift protocols


【解决方案1】:

您可以使用where clause 对泛型类执行此操作:

where 子句使您能够要求关联的类型符合 到某个协议,和/或某些类型参数和 关联类型相同。

要使用它,请将您的属性的类定义为具有type constraint 的通用类,以检查您的属性的type parameter 是否与您所需的基类和协议匹配。

对于您的具体示例,它可能如下所示:

class MyViewController<T where T: UIView, T: Protocol1, T: Protocol2>: UIViewController {
    var myView: T

    // ...
}

【讨论】:

  • 很好的答案。你知道这和class MyViewController&lt;T: UIView, Protocol1, Protocol2&gt;: UIViewController { } 有什么不同吗?
  • 我很确定这完全一样。我想我只是开始使用where 并没有尝试更简洁的格式。
  • 为了使用这个解决方案,如果你初始化控制器,你必须指定 T。如果属性中只有一个对象没问题,但在我的情况下,我有一个数组,它可以包含从基类的不同子类实例化的多个对象。 @MikeS 你会如何解决这个问题?
  • @LukasKubanek 如果我理解您的要求,您可以将属性定义为 Ts 的数组:var myProperty: Array&lt;T&gt; 或 var myProperty: [T]
  • 但在这种情况下,您必须在实例化容器对象时指定具体类型。见gist.github.com/lukaskubanek/ed82cf679c36b5a0b0a1
【解决方案2】:

在 Swift 4 中,这终于成为可能。你可以同时声明一些符合协议的类的变量,像这样:

class ClassA {
    var someVar: String?
}

protocol ProtocolA {}

class ClassB {
    var someOptional: (ClassA & ProtocolA)? // here is optional value
    var some: ClassA & ProtocolA // here is non-optional value; need to provide init though :)
}

【讨论】:

  • 你能告诉我如何提供那个初始化吗?我已经尝试了一段时间没有成功..
  • @jake1981, init(some: ClassA & ProtocolA) { self.some = some }
【解决方案3】:

其中一种可能有点丑陋的方法是为UIView 创建一个包装协议:

protocol UIViewRef {
    var instance: UIView { get }
}

现在可以创建一个实现Protocol1、Protocol2 和UIViewRef 的协议,用于获取UIView 本身:

protocol MyUIViewProtocol: UIViewRef, Protocol1, Protocol2 { }

最后一步是为你的UIViews 实现 UIViewRef 协议,在你的情况下,据我所知,它已经实现了 Protocol1 和 Protocol2:

// SomeOfMyViews already implements Protocol1 and Protocol2
extension SomeOfMyUIViews: MyUIViewProtocol {
    var instance: UIView { return self }
}

因此我们有MyUIViewProtocol,其实现者持有对UIView 的引用,并且他们每个人都实现 Protocol1 和 Protocol2。一个警告 - 要获得 UIView 本身,我们需要从 instance 询问它的引用 财产。例如

// Lets say we're somewhere in a UIViewController
var views: [SomeOfMyUIView] = // Get list of my views
views.forEach { self.view.addSubview($0.instance) }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多