在Swift中,我可以通过如下声明来明确设置变量的类型:
var object: TYPE_NAME
如果我们想更进一步并声明一个符合多个协议的变量,我们可以使用 protocol
声明:
var object: protocol<ProtocolOne,ProtocolTwo>//etc
如果我想声明一个符合一个或多个协议并且也是特定基类类型的对象,该怎么办? Objective-C等价物如下所示:
NSSomething<ABCProtocolOne,ABCProtocolTwo> * object = ...;
在Swift中,我希望它看起来像这样:
var object: TYPE_NAME,ProtocolOne//etc
这使我们能够灵活地处理基类型的实现以及协议中定义的添加接口 .
还有另一种我可能会失踪的更明显的方式吗?
示例
举个例子,假设我有一个 UITableViewCell
工厂负责返回符合协议的单元格 . 我们可以轻松设置一个返回符合协议的单元格的泛型函数:
class CellFactory {
class func createCellForItem<T: UITableViewCell where T:MyProtocol >(item: SpecialItem,tableView: UITableView) -> T {
//etc
}
}
后来我想在利用类型和协议的同时出列这些单元格
var cell: MyProtocol = CellFactory.createCellForItem(somethingAtIndexPath) as UITableViewCell
这会返回错误,因为表视图单元格不符合协议...
我希望能够指定该单元格是 UITableViewCell
并且符合变量声明中的 MyProtocol
?
理由
如果您熟悉Factory Pattern,那么在能够返回实现特定接口的特定类的对象的上下文中这将是有意义的 .
就像在我的例子中一样,有时我们喜欢定义在应用于特定对象时有意义的接口 . 我的表格视图单元格的例子就是这样一个理由 .
虽然提供的类型并不完全符合上面提到的接口,但工厂返回的对象也是如此,因此我希望能够灵活地与基类类型和声明的协议接口进行交互
5 回答
我曾经尝试在Storyboards中链接我的通用交互器连接时遇到类似情况(IB不允许您将插座连接到协议,只有对象实例),我通过简单地使用私有计算机屏蔽基类public ivar来解决这个问题 . 属性 . 虽然这并不妨碍某人本身进行非法分配,但它确实提供了一种方便的方法来安全地防止在运行时与不合格的实例进行任何不必要的交互 . (即防止将委托方法调用到不符合协议的对象 . )
例:
“outputReceiver”被声明为可选,私有“protocolOutputReceiver”也是如此 . 通过始终通过后者(计算属性)访问outputReceiver(a.k.a.委托),我有效地过滤掉任何不符合协议的对象 . 现在我可以简单地使用可选链接来安全地调用委托对象,无论它是否实现协议,甚至是否存在 .
要将此应用于您的情况,您可以让公共ivar为“YourBaseClass?”类型 . (与AnyObject相对),并使用私有计算属性来强制执行协议一致性 . FWIW .
在Swift 4中,现在可以声明一个变量,它是一个类型的子类,同时实现一个或多个协议 .
或作为方法的参数:
Apple在2017年WWDC上宣布了这一消息Session 402: Whats new in Swift
你不能声明变量之类的
也没有声明函数返回类型
你可以像这样声明一个函数参数,但它基本上是向上的 .
截至目前,您所能做的就像:
有了这个,技术上
cell
与asProtocol
相同 .但是,至于编译器,
cell
只有UITableViewCell
的接口,而asProtocol
只有协议接口 . 所以,当你想调用UITableViewCell
的方法时,你必须使用cell
变量 . 如果要调用协议方法,请使用asProtocol
变量 .如果您确定该单元符合协议,则不必使用
if let ... as? ... {}
. 喜欢:也许我错了,但你不是在谈论为
UITableCellView
类添加协议一致性吗?在这种情况下,协议扩展到基类,而不是对象 . 请参阅Declaring Protocol Adoption with an Extension上的Apple文档,在您的情况下会是这样的:除了已经引用的Swift文档之外,还可以参见Nate Cooks文章Generic functions for incompatible types以及其他示例 .
Protocol Adoption将做到这一点,使一个对象遵守给定的协议 . 然而,要注意不利方面,给定协议类型的变量不知道协议之外的任何内容 . 但是这可以通过定义具有所有所需方法/变量/的协议来规避/ ...
如果你想要一个泛型方法,变量以符合协议和基类类型,你可能会运气不好 . 但听起来你需要将协议定义得足够广泛,以便拥有所需的一致性方法,同时又要足够窄,以便可以选择将其用于基类而不需要太多工作(即只是声明一个类符合协议) .
不幸的是,Swift不支持对象级协议一致性 . 但是,有一种尴尬的解决方法可能有助于您的目的 .
然后,无论你需要做什么UIViewController,你都可以访问结构的.viewController方面以及你需要协议方面的任何内容,你可以参考.protocol .
例如:
现在,只要你需要mySpecialViewController做任何与UIViewController相关的事情,你只需要引用mySpecialViewController.viewController,并且只要你需要它来做一些协议功能,你就引用mySpecialViewController.protocol .
希望Swift 4允许我们在将来声明一个附加协议的对象 . 但就目前而言,这是有效的 .
希望这可以帮助!